mush.sh 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. #!/bin/bash
  2. get_largest_nvme_namespace() {
  3. # this function doesn't exist if the version is old enough, so we redefine it
  4. local largest size tmp_size dev
  5. size=0
  6. dev=$(basename "$1")
  7. for nvme in /sys/block/"${dev%n*}"*; do
  8. tmp_size=$(cat "${nvme}"/size)
  9. if [ "${tmp_size}" -gt "${size}" ]; then
  10. largest="${nvme##*/}"
  11. size="${tmp_size}"
  12. fi
  13. done
  14. echo "${largest}"
  15. }
  16. traps() {
  17. set +e
  18. trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
  19. trap 'echo \"${last_command}\" command failed with exit code $?' EXIT
  20. trap '' INT
  21. }
  22. mush_info() {
  23. cat <<-EOF
  24. Welcome to mush, the fakemurk developer shell.
  25. If you got here by mistake, don't panic! Just close this tab and carry on.
  26. This shell contains a list of utilities for performing various actions on a fakemurked chromebook.
  27. This installation of fakemurk has been patched by murkmod. Don't report any bugs you encounter with it to the fakemurk developers.
  28. EOF
  29. }
  30. doas() {
  31. ssh -t -p 1337 -i /rootkey -oStrictHostKeyChecking=no root@127.0.0.1 "$@"
  32. }
  33. runjob() {
  34. trap 'kill -2 $! >/dev/null 2>&1' INT
  35. (
  36. # shellcheck disable=SC2068
  37. $@
  38. )
  39. trap '' INT
  40. }
  41. swallow_stdin() {
  42. while read -t 0 notused; do
  43. read input
  44. done
  45. }
  46. edit() {
  47. if which nano 2>/dev/null; then
  48. doas nano "$@"
  49. else
  50. doas vi "$@"
  51. fi
  52. }
  53. main() {
  54. traps
  55. mush_info
  56. while true; do
  57. cat <<-EOF
  58. (1) Root Shell
  59. (2) Chronos Shell
  60. (3) Plugins
  61. (4) Crosh
  62. (5) Powerwash
  63. (6) Soft Disable Extensions
  64. (7) Hard Disable Extensions
  65. (8) Hard Enable Extensions
  66. (9) Emergency Revert & Re-Enroll
  67. (10) Edit Pollen
  68. (11) Install plugins
  69. (12) Uninstall plugins
  70. (13) Run neofetch
  71. (14) Check for updates
  72. EOF
  73. if ! test -f /mnt/stateful_partition/crouton; then
  74. echo "(15) Install Crouton"
  75. echo "(16) Start Crouton (only run after running above)"
  76. fi
  77. swallow_stdin
  78. read -r -p "> (1-16): " choice
  79. case "$choice" in
  80. 1) runjob doas bash ;;
  81. 2) runjob bash ;;
  82. 3) runjob show_plugins ;;
  83. 4) runjob /usr/bin/crosh.old ;;
  84. 5) runjob powerwash ;;
  85. 6) runjob softdisableext ;;
  86. 7) runjob harddisableext ;;
  87. 8) runjob hardenableext ;;
  88. 9) runjob revert ;;
  89. 10) runjob edit /etc/opt/chrome/policies/managed/policy.json ;;
  90. 11) runjob install_plugins ;;
  91. 12) runjob uninstall_plugins ;;
  92. 13) runjob do_neofetch ;;
  93. 14) runjob do_updates && exit 0 ;;
  94. 15) runjob install_crouton ;;
  95. 16) runjob run_crouton ;;
  96. *) echo "----- Invalid option ------" ;;
  97. esac
  98. done
  99. }
  100. do_updates() {
  101. doas "bash <(curl -SLk https://raw.githubusercontent.com/rainestorme/murkmod/main/murkmod.sh)"
  102. exit
  103. }
  104. do_neofetch() {
  105. curl https://raw.githubusercontent.com/dylanaraps/neofetch/master/neofetch | bash
  106. }
  107. show_plugins() {
  108. clear
  109. plugins_dir="/mnt/stateful_partition/murkmod/plugins"
  110. plugin_files=()
  111. while IFS= read -r -d '' file; do
  112. plugin_files+=("$file")
  113. done < <(find "$plugins_dir" -type f -name "*.sh" -print0)
  114. plugin_info=()
  115. for file in "${plugin_files[@]}"; do
  116. plugin_script=$file
  117. PLUGIN_NAME=$(grep -o 'PLUGIN_NAME=".*"' "$plugin_script" | cut -d= -f2-)
  118. PLUGIN_FUNCTION=$(grep -o 'PLUGIN_FUNCTION=".*"' "$plugin_script" | cut -d= -f2-)
  119. PLUGIN_DESCRIPTION=$(grep -o 'PLUGIN_DESCRIPTION=".*"' "$plugin_script" | cut -d= -f2-)
  120. PLUGIN_AUTHOR=$(grep -o 'PLUGIN_AUTHOR=".*"' "$plugin_script" | cut -d= -f2-)
  121. PLUGIN_VERSION=$(grep -o 'PLUGIN_VERSION=".*"' "$plugin_script" | cut -d= -f2-)
  122. plugin_info+=("$PLUGIN_FUNCTION (provided by $PLUGIN_NAME)")
  123. done
  124. # Print menu options
  125. for i in "${!plugin_info[@]}"; do
  126. printf "%s. %s\n" "$((i+1))" "${plugin_info[$i]}"
  127. done
  128. # Prompt user for selection
  129. read -p "> Select a plugin (or q to quit): " selection
  130. if [ "$selection" = "q" ]; then
  131. return 0
  132. fi
  133. # Validate user's selection
  134. if ! [[ "$selection" =~ ^[1-9][0-9]*$ ]]; then
  135. echo "Invalid selection. Please enter a number between 0 and ${#plugin_info[@]}"
  136. return 1
  137. fi
  138. if ((selection < 1 || selection > ${#plugin_info[@]})); then
  139. echo "Invalid selection. Please enter a number between 0 and ${#plugin_info[@]}"
  140. return 1
  141. fi
  142. # Get plugin function name and corresponding file
  143. selected_plugin=${plugin_info[$((selection-1))]}
  144. selected_file=${plugin_files[$((selection-1))]}
  145. # Execute the plugin
  146. bash <(cat $selected_file) # weird syntax due to noexec mount
  147. return 0
  148. }
  149. install_plugins() {
  150. local raw_url="https://raw.githubusercontent.com/rainestorme/murkmod/main/plugins"
  151. echo "Find a plugin you want to install here: "
  152. echo " https://github.com/rainestorme/murkmod/tree/main/plugins"
  153. echo "Enter the name of a plugin (including the .sh) to install it (or q to quit):"
  154. read -r plugin_name
  155. while [[ $plugin_name != "q" ]]; do
  156. local plugin_url="$raw_url/$plugin_name"
  157. local plugin_info=$(curl -s $plugin_url)
  158. if [[ $plugin_info == *"Not Found"* ]]; then
  159. echo "Plugin not found"
  160. else
  161. doas "pushd /mnt/stateful_partition/murkmod/plugins && curl https://raw.githubusercontent.com/rainestorme/murkmod/main/plugins/$plugin_name -O && popd"
  162. echo "Installed $plugin_name"
  163. fi
  164. echo "Enter the name of a plugin (including the .sh) to install (or q to quit):"
  165. read -r plugin_name
  166. done
  167. }
  168. uninstall_plugins() {
  169. clear
  170. plugins_dir="/mnt/stateful_partition/murkmod/plugins"
  171. plugin_files=()
  172. while IFS= read -r -d '' file; do
  173. plugin_files+=("$file")
  174. done < <(find "$plugins_dir" -type f -name "*.sh" -print0)
  175. plugin_info=()
  176. for file in "${plugin_files[@]}"; do
  177. plugin_script=$file
  178. PLUGIN_NAME=$(grep -o 'PLUGIN_NAME=.*' "$plugin_script" | cut -d= -f2-)
  179. PLUGIN_FUNCTION=$(grep -o 'PLUGIN_FUNCTION=.*' "$plugin_script" | cut -d= -f2-)
  180. PLUGIN_DESCRIPTION=$(grep -o 'PLUGIN_DESCRIPTION=.*' "$plugin_script" | cut -d= -f2-)
  181. PLUGIN_AUTHOR=$(grep -o 'PLUGIN_AUTHOR=.*' "$plugin_script" | cut -d= -f2-)
  182. PLUGIN_VERSION=$(grep -o 'PLUGIN_VERSION=.*' "$plugin_script" | cut -d= -f2-)
  183. plugin_info+=("$PLUGIN_NAME (version $PLUGIN_VERSION by $PLUGIN_AUTHOR)")
  184. done
  185. if [ ${#plugin_info[@]} -eq 0 ]; then
  186. echo "No plugins installed. Select "
  187. return
  188. fi
  189. while true; do
  190. echo "Installed plugins:"
  191. for i in "${!plugin_info[@]}"; do
  192. echo "$(($i+1)). ${plugin_info[$i]}"
  193. done
  194. echo "0. Exit back to mush"
  195. read -r -p "Enter a number to uninstall a plugin, or 0 to exit: " choice
  196. if [ "$choice" -eq 0 ]; then
  197. clear
  198. return
  199. fi
  200. index=$(($choice-1))
  201. if [ "$index" -lt 0 ] || [ "$index" -ge ${#plugin_info[@]} ]; then
  202. echo "Invalid choice."
  203. continue
  204. fi
  205. plugin_file="${plugin_files[$index]}"
  206. PLUGIN_NAME=$(grep -o 'PLUGIN_NAME=".*"' "$plugin_file" | cut -d= -f2-)
  207. PLUGIN_FUNCTION=$(grep -o 'PLUGIN_FUNCTION=".*"' "$plugin_file" | cut -d= -f2-)
  208. PLUGIN_DESCRIPTION=$(grep -o 'PLUGIN_DESCRIPTION=".*"' "$plugin_file" | cut -d= -f2-)
  209. PLUGIN_AUTHOR=$(grep -o 'PLUGIN_AUTHOR=".*"' "$plugin_file" | cut -d= -f2-)
  210. PLUGIN_VERSION=$(grep -o 'PLUGIN_VERSION=".*"' "$plugin_file" | cut -d= -f2-)
  211. plugin_name="$PLUGIN_NAME (version $PLUGIN_VERSION by $PLUGIN_AUTHOR)"
  212. read -r -p "Are you sure you want to uninstall $plugin_name? [y/n] " confirm
  213. if [ "$confirm" == "y" ]; then
  214. doas rm "$plugin_file"
  215. echo "$plugin_name uninstalled."
  216. unset plugin_info[$index]
  217. plugin_info=("${plugin_info[@]}")
  218. fi
  219. done
  220. }
  221. powerwash() {
  222. echo "Are you sure you wanna powerwash? This will remove all user accounts and data, but won't remove fakemurk."
  223. sleep 2
  224. echo "(Press enter to continue, ctrl-c to cancel)"
  225. swallow_stdin
  226. read -r
  227. doas echo "fast safe" >/mnt/stateful_partition/factory_install_reset
  228. doas reboot
  229. exit
  230. }
  231. revert() {
  232. echo "This option will re-enroll your chromebook restore to before fakemurk was run. This is useful if you need to quickly go back to normal"
  233. echo "This is *permanent*. You will not be able to fakemurk again unless you re-run everything from the beginning."
  234. echo "Are you sure - 100% sure - that you want to continue? (press enter to continue, ctrl-c to cancel)"
  235. swallow_stdin
  236. read -r
  237. sleep 4
  238. echo "Setting kernel priority"
  239. DST=/dev/$(get_largest_nvme_namespace)
  240. if doas "(($(cgpt show -n "$DST" -i 2 -P) > $(cgpt show -n "$DST" -i 4 -P)))"; then
  241. doas cgpt add "$DST" -i 2 -P 0
  242. doas cgpt add "$DST" -i 4 -P 1
  243. else
  244. doas cgpt add "$DST" -i 4 -P 0
  245. doas cgpt add "$DST" -i 2 -P 1
  246. fi
  247. echo "Setting vpd"
  248. doas vpd.old -i RW_VPD -s check_enrollment=1
  249. doas vpd.old -i RW_VPD -s block_devmode=1
  250. doas crossystem.old block_devmode=1
  251. echo "Done. Press enter to reboot"
  252. swallow_stdin
  253. read -r
  254. echo "Bye!"
  255. sleep 2
  256. doas reboot
  257. sleep 1000
  258. echo "Your chromebook should have rebooted by now. If your chromebook doesn't reboot in the next couple of seconds, press Esc+Refresh to do it manually."
  259. }
  260. harddisableext() { # calling it "hard disable" because it only reenables when you press
  261. read -r -p "Enter extension ID > " extid
  262. chmod 000 "/home/chronos/user/Extensions/$extid"
  263. kill -9 $(pgrep -f "\-\-extension\-process")
  264. }
  265. hardenableext() {
  266. read -r -p "Enter extension ID > " extid
  267. chmod 777 "/home/chronos/user/Extensions/$extid"
  268. kill -9 $(pgrep -f "\-\-extension\-process")
  269. }
  270. softdisableext() {
  271. echo "Extensions will stay disabled until you press Ctrl+c or close this tab"
  272. while true; do
  273. kill -9 $(pgrep -f "\-\-extension\-process") 2>/dev/null
  274. sleep 0.5
  275. done
  276. }
  277. install_crouton() {
  278. echo "Installing Crouton on /mnt/stateful_partition"
  279. doas "bash <(curl -SLk https://goo.gl/fd3zc) -t xfce -r bullseye" && touch /mnt/stateful_partition/crouton
  280. }
  281. run_crouton() {
  282. echo "Use Crtl+Shift+Alt+Forward and Ctrl+Shift+Alt+Back to toggle between desktops"
  283. doas "startxfce4"
  284. }
  285. if [ "$0" = "$BASH_SOURCE" ]; then
  286. stty sane
  287. main
  288. fi