rescue.cgi 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. #!/usr/bin/haserl --shell=/bin/bash --upload-limit=32768 --upload-dir=/www/tmp
  2. <%# upload limit: 32Mb %>
  3. <%
  4. _WWW='/www'
  5. _TMP="${_WWW}/tmp"
  6. _LOG="${_WWW}/systemupdate.log" ## safe persistently
  7. _DEBUG=1
  8. err() {
  9. _ERR="$?"
  10. [[ "$_ERR" -gt 0 ]] || return 0
  11. log "$1"
  12. head "${2:='400'}"
  13. exit "$_ERR"
  14. }
  15. logThis() {
  16. [[ "$_DEBUG" -gt 0 ]] || return 0
  17. local _TYPE='I:'
  18. [[ "$_ERR" -gt 0 ]] && _TYPE='E:'
  19. local _TIME; printf -v _TIME '%(%d.%m.%Y %H:%M:%S)T' -1
  20. printf '%b\n' "$_TIME $_TYPE ${@} " >> "$_LOG"
  21. [[ "$_DEBUG" -gt 1 ]] && printf '%b\n' "[verbose] $_TYPE ${1}"
  22. }
  23. headerPrint() {
  24. case "$1" in
  25. 200|'') printf '%b' 'HTTP/1.1 200 OK\r\n';;
  26. 301) printf '%b' "HTTP/1.1 301 Moved Permanently\r\nLocation: $HTTP_REFERER\r\n";;
  27. 403) printf '%b' 'HTTP/1.1 403 Forbidden\r\n';;
  28. 405) printf '%b' 'HTTP/1.1 405 Method Not Allowed\r\n';;
  29. 406) printf '%b' 'HTTP/1.1 406 Not Acceptable\r\n';;
  30. *) printf '%b' 'HTTP/1.1 400 Bad Request\r\n';;
  31. esac
  32. printf '%b' 'Content-Type: text/html\r\n\r\n';
  33. }
  34. setQueryVars() {
  35. env
  36. }
  37. runSuid() {
  38. local _SID=$(/usr/bin/ps -p $$ -o sid=) ## pass session id to the child
  39. local _CMD=$@
  40. sudo ./suid.sh $_CMD $_SID 2>/dev/null
  41. }
  42. getQueryFile() {
  43. local _UPLD="${HASERL_fwupload_path##*/}"
  44. logThis "'multipart': decoding stream"
  45. mv "$_TMP/$_UPLD" "$_TMP/fwupload.bin" 2>/dev/null || _ERR=$?
  46. if [[ $_ERR -gt 0 ]]; then
  47. showMesg 'Firmware upload has failed' 'Reboot your Superglue server and try again'
  48. fi
  49. }
  50. validIp() {
  51. local _IP=$1
  52. local _RET=1
  53. if [[ $_IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
  54. OIFS=$IFS
  55. IFS='.'
  56. _IP=($_IP)
  57. IFS=$OIFS
  58. [[ ${_IP[0]} -le 255 && ${_IP[1]} -le 255 && ${_IP[2]} -le 255 && ${_IP[3]} -le 255 ]]
  59. _RET=$?
  60. fi
  61. return $_RET
  62. }
  63. pwdChange() {
  64. if [[ ! -z "${_pwd##$_pwdd}" ]]; then
  65. _ERR=1
  66. showMesg 'Passwords did not match'
  67. fi
  68. if [[ ${#_pwd} -lt 6 ]]; then
  69. _ERR=1
  70. showMesg 'Password must be at least 6 characters long'
  71. fi
  72. runSuid "echo -e \"$_pwd\n$_pwd\" | passwd root"
  73. runSuid "echo $(htDigest $_pwd) > $_PWDFILE"
  74. _ERR=$?
  75. if [[ $_ERR -gt 0 ]]; then
  76. showMesg 'Password change failed'
  77. else
  78. showMesg 'Password is changed'
  79. fi
  80. }
  81. lanAddr() {
  82. logThis "new LAN addr is: $_laddr"
  83. validIp $_laddr || showMesg 'Not valid network address'
  84. doUci set laddr $_laddr
  85. _ERR=$?
  86. if [[ $_ERR -gt 0 ]]; then
  87. showMesg 'Setting network address failed'
  88. else
  89. (sleep 1; doUci commit network; doUci commit wireless;)&
  90. showMesg 'New network address is set' "Your server is now accessible under <a href='http://superglue.local/admin'>http://superglue.local/admin</a>"
  91. fi
  92. }
  93. wanSet() {
  94. if [[ ! -z $_wanifname ]]; then
  95. ## eth and wlan wan cases are different!
  96. ## eth wan requires:
  97. ## config interface 'wan'
  98. ## option ifname 'eth0'
  99. ##
  100. ## config wifi-iface
  101. ## option device 'radio0'
  102. ## option network 'wan'
  103. ## option disabled '1' (or no 'config wifi-iface' section at all)
  104. ##
  105. ## wlan wan requires:
  106. ## config interface 'wan'
  107. ## option proto 'dhcp'
  108. ## (without 'option ifname' specified!)
  109. ##
  110. ## config wifi-iface
  111. ## option device 'radio0'
  112. ## option network 'wan'
  113. logThis "wan.ifname=$_wanifname"
  114. if [[ $_wanifname == 'eth0' ]]; then
  115. doUci set wanifname $_wanifname
  116. doUci set wanwifacedis '1'
  117. elif [[ $_wanifname == 'wlan1' ]]; then
  118. doUci set wanifname ''
  119. doUci set wanwifacedis ''
  120. fi
  121. if [[ $_wanproto == 'dhcp' ]]; then
  122. doUci set wanproto dhcp
  123. elif [[ $_wanproto == 'static' ]]; then
  124. logThis "wan.ipaddr=$_wanipaddr"
  125. doUci set wanproto static
  126. doUci set wanipaddr $_wanipaddr
  127. doUci set wannetmask $_wannetmask
  128. fi
  129. if [[ $_wanifname == 'wlan1' ]]; then
  130. ssidChange || showMesg 'Wireless changes failed'
  131. fi
  132. ## background the following
  133. doUci commit network &&
  134. showMesg 'Internet connection is configured' 'Waiting for device to get ready' ||
  135. showMesg 'Configuring Internet connection failed'
  136. fi
  137. logThis "new WAN iface is: $_wanifname"
  138. }
  139. ssidChange() {
  140. ## check for iface
  141. [[ ! $_iface =~ ^('wan'|'lan')$ ]] && showMesg 'Error changing wireless settings' 'unknown/unconfigured interface'
  142. logThis "$_iface is being set"
  143. _p=$_iface
  144. ## default enc for now
  145. local _enc='psk2'
  146. if [[ $_iface == 'wan' ]]; then
  147. local _mode='sta'
  148. local _ssid="${_wanssid}"
  149. local _key="${_wankey}"
  150. else
  151. local _mode='ap'
  152. local _ssid="${_lanssid}"
  153. local _key="${_lankey}"
  154. fi
  155. logThis "ssid: $_ssid [$_mode], key: $_key [$_enc]"
  156. logThis $_wanssid
  157. if [[ ${#_ssid} -lt 4 ]]; then
  158. _ERR=1
  159. showMesg 'SSID must be at least 4 characters long'
  160. fi
  161. doUci set $_p'ssid' "${_ssid}"
  162. _ERR=$?
  163. [[ $_ERR -gt 0 ]] && showMesg 'New SSID is not set'
  164. if [[ -z $_key ]]; then
  165. ## if key is empty set encryption to none and remove key
  166. doUci set $_p'key' && doUci set $_p'enc' 'none'
  167. _ERR=$?
  168. else
  169. if [[ ${#_key} -lt 8 ]]; then
  170. _ERR=1
  171. showMesg 'Passphrase must be at least 8 characters long'
  172. fi
  173. doUci set $_p'key' "${_key}" && doUci set $_p'enc' "${_enc}"
  174. _ERR=$?
  175. [[ $_ERR -gt 0 ]] && showMesg 'Passphrase is not set'
  176. fi
  177. [[ $_ERR -gt 0 ]] && return $_ERR ##showMesg 'Wireless changes failed'
  178. doUci commit wireless ##&& showMesg 'Wireless changes applied'
  179. }
  180. #showError() {
  181. # headerPrint 406
  182. # logThis "$@"
  183. # echo "ERROR: $@"
  184. # exit 1
  185. #}
  186. showMesg() {
  187. logThis "$@"
  188. local _MSG=$1
  189. local _SUBMSG=$2
  190. _MSG=${_MSG:='Not defined'}
  191. _SUBMSG=${_SUBMSG:='back to control panel in a second..'}
  192. if [[ $_ERR -gt 0 ]]; then
  193. local _TYPE='ERROR: '
  194. headerPrint 406
  195. else
  196. local _TYPE='OK: '
  197. headerPrint 200
  198. fi
  199. htmlHead "<meta http-equiv='refresh' content='3;url=${HTTP_REFERER}'>"
  200. echo "<body>
  201. <h1>Superglue system update</h1>
  202. <hr>
  203. <h2 style='display:inline'>$_TYPE $_MSG</h2>
  204. <span style='display:inline; margin-left: 50px;'>$_SUBMSG</span>
  205. <hr>
  206. </body></html>"
  207. exit 0
  208. }
  209. updateFw() {
  210. logThis "updating fw"
  211. _FWFILE="${_TMP}/fwupload.bin"
  212. logThis "fwfile is: $(ls -lad $_FWFILE)"
  213. _OUT="$(/sbin/sysupgrade -T $_FWFILE 2>&1)"
  214. _ERR=$?
  215. [[ $_ERR -gt 0 ]] && showMesg "$_OUT"
  216. _OUT="$(runSuid /sbin/mtd -e firmware -q write $_FWFILE firmware)"
  217. _ERR=$?
  218. [[ $_ERR -gt 0 ]] && showMesg "update failed, $_OUT"
  219. _OUT="$(/sbin/mtd verify $_FWFILE firmware_2>&1)"
  220. _ERR=$?
  221. [[ $_ERR -gt 0 ]] && showMesg "update check failed, $_OUT"
  222. runSuid reboot
  223. showMesg 'Firmware update is completed, rebooting..' 'this might take up to 60 seconds'
  224. }
  225. rebootNow() {
  226. logThis "reboot: now!"
  227. runSuid reboot
  228. showMesg 'Rebooting..' 'this might take up to 60 seconds'
  229. }
  230. doUci() {
  231. local _CMD=''
  232. local _ARG=''
  233. case $1 in
  234. get|set|commit) _CMD=$1;;
  235. *) logThis 'bad UCI command'; headerPrint 405; echo 'bad UCI command'; exit 1 ;;
  236. esac
  237. case $2 in
  238. lanssid) _ARG='wireless.@wifi-iface[0].ssid';;
  239. lanenc) _ARG='wireless.@wifi-iface[0].encryption';;
  240. lankey) _ARG='wireless.@wifi-iface[0].key';;
  241. lanipaddr) _ARG='network.lan.ipaddr';;
  242. wanifname) _ARG='network.wan.ifname';;
  243. wanproto) _ARG='network.wan.proto';;
  244. wanipaddr) _ARG='network.wan.ipaddr';;
  245. wannetmask) _ARG='network.wan.netmask';;
  246. wanwifacedis) _ARG='wireless.@wifi-iface[1].disabled';;
  247. wanssid) _ARG='wireless.@wifi-iface[1].ssid';;
  248. wanenc) _ARG='wireless.@wifi-iface[1].encryption';;
  249. wankey) _ARG='wireless.@wifi-iface[1].key';;
  250. *) if [[ $_CMD == 'commit' ]]; then
  251. _ARG=$2
  252. else
  253. logThis "bad UCI entry: $2"
  254. _ERR=1
  255. showMesg 'bad UCI entry'
  256. fi ;;
  257. esac
  258. if [[ $_CMD == 'get' ]]; then
  259. if [ ! -z $_ARG ]; then
  260. /sbin/uci -q get $_ARG || return $?
  261. fi
  262. fi
  263. if [[ $_CMD == 'set' ]]; then
  264. local _VAL=$3
  265. if [ -z $_VAL ]; then
  266. logThis "empty $_ARG value, removing record"
  267. runSuid /sbin/uci delete $_ARG || ( echo "uci delete $_ARG: error"; exit 1; )
  268. fi
  269. if [ ! -z $_ARG ]; then
  270. logThis "setting $_ARG value"
  271. runSuid /sbin/uci set $_ARG=$_VAL || ( echo "uci set $_ARG: error"; exit 1; )
  272. fi
  273. fi
  274. if [[ $_CMD == 'commit' ]]; then
  275. runSuid /sbin/uci commit $_ARG|| echo "uci commit $_ARG: error"
  276. if [[ "$_ARG" == 'wireless' ]]; then
  277. runSuid /sbin/wifi || echo 'wifi: error'
  278. fi
  279. if [[ "$_ARG" == 'network' ]]; then
  280. runSuid /etc/init.d/dnsmasq restart && runSuid /etc/init.d/network restart || echo 'network: error'
  281. fi
  282. fi
  283. }
  284. getStat() {
  285. . /usr/share/libubox/jshn.sh
  286. local _IFACE=$1
  287. local _IFSTAT=$(runSuid ubus call network.interface.wan status 2>/dev/null)
  288. logThis "$_IFSTAT"
  289. json_get_type _IFSTAT ipv4_address
  290. if json_get_type _IFSTAT ipv4_address && [[ "$_IFSTAT" == 'array' ]]; then
  291. json_select ipv4_address
  292. json_get_type _IFSTAT 1
  293. if [[ "$_IFSTAT" == 'object' ]]; then
  294. json_select 1
  295. json_get_var IP4 address
  296. json_get_var Subnet4 mask
  297. [[ "$IP4" != '' ]] && [[ "$Subnet4" != '' ]] && IP4="$IP4/$Subnet4"
  298. fi
  299. fi
  300. logThis $IP4
  301. }
  302. htmlHead() {
  303. echo "<!-- obnoxious code below, keep your ports tight -->
  304. <!doctype html>
  305. <html>
  306. <head><title>SuperGlue | System update</title>
  307. $@
  308. <link rel='stylesheet' type='text/css' href='http://${HTTP_HOST}/resources/admin/admin.css'>
  309. </head>"
  310. }
  311. if [[ "${REQUEST_METHOD^^}" == "POST" ]]; then
  312. [[ $CONTENT_LENGTH -gt 0 ]] || err 'content length is zero, 301 back to referer' '301'
  313. case "${CONTENT_TYPE^^}" in
  314. APPLICATION/X-WWW-FORM-URLENCODED*) setQueryVars;;
  315. MULTIPART/FORM-DATA*) getQueryFile;;
  316. *) _ERR=1; _OUT='this is not a post';;
  317. esac
  318. case $REQUEST_URI in
  319. *pwdchange) pwdChange;;
  320. *ssidchange) ssidChange;;
  321. *lanaddr) lanAddr;;
  322. *updatefw) updateFw;;
  323. *rebootnow) rebootNow;;
  324. *wan) wanSet;;
  325. *) logThis 'bad action'; headerPrint 405;
  326. echo 'no such thing'; exit 1;;
  327. esac
  328. fi
  329. headerPrint 200
  330. ## html head
  331. htmlHead
  332. sgver=$(cat /etc/superglue_version)
  333. devmod=$(cat /etc/superglue_model)
  334. openwrt=$(cat /etc/openwrt_version)
  335. wanifname=$(doUci get wanifname || echo 'wlan0') ## TODO fix this
  336. wanproto=$(doUci get wanproto)
  337. wanipaddr=$(doUci get wanipaddr)
  338. wannetmask=$(doUci get wannetmask)
  339. wanssid=$(doUci get wanssid)
  340. wankey=$(doUci get wankey)
  341. echo "<body>
  342. <img src='/resources/images/superglue-logo.png' id='sg-logo'>
  343. <h2 style='display:inline'>Superglue system update</h2>
  344. <span style='display:block;'>System version: $sgver | Device: $devmod</span>
  345. <span style='display:block;'>$(uptime)</span>
  346. <hr>
  347. <span class='title2'>Firmware update:</span>
  348. <p>The main purpose of Superglue <b>system update mode</b> is to ensure smooth and simple upgrades to the latest versions of Superglue firmware (OS) during the period of active project development. These updates help us get rid of the bugs and introduce new features (and sometimes, the other way around)</p>
  349. <p>Before you begin, please make sure to obtain the latest firmware by visiting our <a href='http://discourse.superglue.it/category/superglue/l/latest' target='_blank'>online users comminuty</a> or directly via the <a href='http://dev.superglue.it/firmware/latest' target='_blank'>Superglue firmware repository</a>.</p>
  350. <p>Once you are ready, upload the firmware update file using the form below:</p>
  351. <form method='post' action='/systemupdate/updatefw' enctype='multipart/form-data' name='fwupdate'>
  352. <div id='uploadbox'>
  353. <input id='uploadfile' placeholder='Choose file' disabled='disabled' style='width:400px'>
  354. <input id='uploadbtn' name='fwupload' type='file'>
  355. </div>
  356. <input type='submit' value='Upload'>
  357. </form>
  358. <p>Configuration options below are optional.<br>Unless you upgrade the current firmware any changes done to the setting will not be saved.</p>
  359. <hr>
  360. <br><br>
  361. Internet connection:
  362. <form method='post' action='/systemupdate/wan' name='wan' onchange='formChange();'>
  363. <div style='display:inline-flex'>
  364. <div style='display:inline-block;'>
  365. <select name='wanifname' id='wanifname' style='display:block'>
  366. <option value='eth0' id='eth' $([[ $wanifname =~ ('eth') ]] && echo 'selected')>Wired (WAN port)</option>
  367. <option value='wlan1' id='wlan' $([[ $wanifname =~ ('wlan') ]] && echo 'selected')>Wireless (Wi-Fi)</option>
  368. </select>
  369. <fieldset id='wanwifi' class='hide'>
  370. <input type='text' name='wanssid' value='$wanssid'>
  371. <input type='password' name='wankey' value='$wankey'>
  372. </fieldset>
  373. </div>
  374. <div style='display:inline-block;'>
  375. <select name='wanproto' id='wanproto' style='display:block'>
  376. <option value='dhcp' name='dhcp' id='dhcp' $([[ $wanproto == 'dhcp' ]] && echo 'selected')>Automatic (DHCP)</option>
  377. <option value='stat' name='dhcp' id='stat' $([[ $wanproto == 'static' ]] && echo 'selected')>Manual (Static IP)</option>
  378. </select>
  379. <fieldset id='wanaddr' class='hide' >
  380. <input type='text' name='wanipaddr' id='wanipaddr' value='$wanipaddr'>
  381. <input type='text' name='wangw' id='wannetmask' value='$wannetmask'>
  382. </fieldset>
  383. </div>
  384. </div>
  385. <input type='hidden' name='iface' value='wan' class='inline'>
  386. <input type='submit' value='Apply'>
  387. </form>
  388. <hr>
  389. Local wireless network:
  390. <form method='post' action='/systemupdate/ssidchange'>
  391. <div style='display:inline-flex'>
  392. <div style='display:inline-block;'>
  393. <input type='text' name='lanssid' value='$(doUci get lanssid)'>
  394. <input type='password' name='lankey' value='$(doUci get lankey)'>
  395. </div>
  396. <div style='display:inline-block;'>
  397. <input type='text' name='lanipaddr' value='$(doUci get lanipaddr)'>
  398. <input type='hidden' name='iface' value='lan' class='inline'>
  399. </div>
  400. </div>
  401. <input type='submit' value='Apply'>
  402. </form>
  403. <hr>
  404. <form action='/systemupdate/rebootnow' method='post' class='inline'>
  405. <input type='hidden' name='reboot' value='now' class='inline'>
  406. <input type='submit' value='Reboot' class='inline'>
  407. </form>
  408. <form action='http://logout@${HTTP_HOST}/systemupdate' method='get' class='inline'>
  409. <input type='submit' value='Logout' class='inline'>
  410. </form>
  411. <hr>
  412. Memory:
  413. <pre>$(free)</pre>
  414. <hr>
  415. Storage:
  416. <pre>$(df -h)</pre>
  417. <hr>
  418. Environment:
  419. <pre>$(env)</pre>
  420. <hr>
  421. </body>
  422. <script type='text/javascript' src='http://${HTTP_HOST}/resources/admin/admin.js'></script>
  423. </html>"
  424. %>