session.tcl 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888
  1. #!/usr/bin/env tclsh
  2. #
  3. # Copyright (c) 2015-2017 OpenIndex.de
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a copy
  6. # of this software and associated documentation files (the "Software"), to deal
  7. # in the Software without restriction, including without limitation the rights
  8. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. # copies of the Software, and to permit persons to whom the Software is
  10. # furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. # THE SOFTWARE.
  22. #
  23. namespace eval ::support::session {
  24. variable PIDS {}
  25. variable LOG_FILE
  26. variable WORK_DIR
  27. variable WORK_OSXVNC_EXE
  28. variable WORK_X11VNC_EXE
  29. variable WORK_TIGHTVNC_EXE
  30. variable WORK_SSH_EXE
  31. variable WORK_RUNNING_EXE
  32. variable VNC_APP_NAME
  33. variable VNC_APP_VERSION
  34. variable VNC_APP_LICENSE
  35. variable VNC_HOST
  36. variable VNC_PORT
  37. variable VNC_EXE
  38. variable VNC_PARAMETERS
  39. variable SSH_APP_NAME
  40. variable SSH_APP_VERSION
  41. variable SSH_APP_LICENSE
  42. variable SSH_APP_PROVIDED 0
  43. variable SSH_EXE
  44. variable SSH_PORT
  45. variable SSH_USER
  46. variable SSH_KEY
  47. variable SSH_KEY_PROVIDED 0
  48. variable SSH_ENABLED 0
  49. variable USE_PROVIDED_VNC_APP 0
  50. variable USE_PROVIDED_SSH_APP 0
  51. variable USE_PROVIDED_SSH_KEY 0
  52. # Initialize VNC environment.
  53. proc init {} {
  54. if {[::support::utils::is_darwin]} {
  55. init_darwin
  56. } elseif {[::support::utils::is_linux]} {
  57. init_linux
  58. } elseif {[::support::utils::is_windows]} {
  59. init_windows
  60. } else {
  61. error "Your operating system is not supported!"
  62. }
  63. # Get path of the session log file.
  64. variable LOG_FILE [file join $::support::APP_DIR [format "%s-session.log" $::support::LOG_NAME]]
  65. file delete -force $LOG_FILE
  66. # Init default vnc settings.
  67. variable VNC_HOST [::support::Config::getSessionValue "host" ""]
  68. variable VNC_PORT [::support::Config::getSessionValue "port" "5500"]
  69. variable VNC_EXE [::support::Config::getSessionValue "vnc-application" ""]
  70. variable VNC_PARAMETERS [::support::Config::getSessionValue "vnc-parameters" ""]
  71. if {$VNC_EXE != ""} {
  72. variable USE_PROVIDED_VNC_APP 0
  73. } else {
  74. variable USE_PROVIDED_VNC_APP 1
  75. }
  76. # Init default ssh settings.
  77. variable SSH_PORT [::support::Config::getSessionValue "ssh-port" "22"]
  78. variable SSH_USER [::support::Config::getSessionValue "ssh-user" ""]
  79. variable SSH_ENABLED [string tolower [::support::Config::getSessionValue "ssh-enabled" "no"]]
  80. if {$SSH_ENABLED == "yes" || $SSH_ENABLED == "1" || $SSH_ENABLED == "true"} {
  81. variable SSH_ENABLED 1
  82. } else {
  83. variable SSH_ENABLED 0
  84. }
  85. # Detect default ssh key.
  86. variable SSH_KEY [::support::Config::getSessionValue "ssh-keyfile" ""]
  87. if {[file isfile [file join $::support::APP_DIR "ssh.key"]]} {
  88. variable SSH_KEY [file join $::support::APP_DIR "ssh.key"]
  89. }
  90. if {[file isfile [file join $::support::DATA_DIR "ssh.key"]]} {
  91. variable SSH_KEY_PROVIDED 1
  92. variable USE_PROVIDED_SSH_KEY 1
  93. }
  94. # Detect default ssh application.
  95. variable SSH_EXE [::support::Config::getSessionValue "ssh-application" ""]
  96. if {[::support::utils::is_darwin] || [::support::utils::is_linux]} {
  97. if {$SSH_EXE == "" || ![file isfile $SSH_EXE]} {
  98. set SSH_EXE [::support::utils::get_application ssh]
  99. }
  100. }
  101. }
  102. # Initialize VNC environment for Mac OS X.
  103. proc init_darwin {} {
  104. variable VNC_APP_NAME "OSXvnc"
  105. variable VNC_APP_VERSION "5.0.1"
  106. variable VNC_APP_LICENSE "GPLv2"
  107. variable SSH_APP_NAME "OpenSSH"
  108. variable SSH_APP_VERSION ""
  109. variable SSH_APP_LICENSE ""
  110. variable SSH_APP_PROVIDED 0
  111. variable USE_PROVIDED_SSH_APP 0
  112. # Prepare work directory.
  113. variable WORK_DIR [file join $::support::TEMP_DIR "work"]
  114. file copy [file join $::support::DATA_DIR "darwin"] $WORK_DIR
  115. # Get path to OSXvnc-server in work directory.
  116. variable WORK_OSXVNC_EXE [file join $WORK_DIR "osxvnc" "OSXvnc-server"]
  117. if {![file isfile $WORK_OSXVNC_EXE]} {
  118. puts "ERROR: Can't find packaged OSXvnc-server!"
  119. puts "at $WORK_OSXVNC_EXE"
  120. } else {
  121. exec chmod u+x $WORK_OSXVNC_EXE
  122. }
  123. }
  124. # Initialize VNC environment for Linux.
  125. proc init_linux {} {
  126. variable VNC_APP_NAME "x11vnc"
  127. variable VNC_APP_VERSION "0.9.13"
  128. variable VNC_APP_LICENSE "GPLv2"
  129. variable SSH_APP_NAME "OpenSSH"
  130. variable SSH_APP_VERSION ""
  131. variable SSH_APP_LICENSE ""
  132. variable SSH_APP_PROVIDED 0
  133. variable USE_PROVIDED_SSH_APP 0
  134. # Detect platform (amd64 or i386).
  135. set platform $::tcl_platform(machine)
  136. if {$platform == "x86_64" || $platform == "amd64"} {
  137. set arch "amd64"
  138. } elseif {$platform == "i686" || $platform == "i586" || $platform == "i386"} {
  139. set arch "i386"
  140. } else {
  141. error "VNC is not supported for the $platform platform!"
  142. }
  143. # Prepare work directory.
  144. variable WORK_DIR [file join $::support::TEMP_DIR "work"]
  145. file copy [file join $::support::DATA_DIR "linux-$arch"] $WORK_DIR
  146. # Get path to x11vnc in work directory.
  147. variable WORK_X11VNC_EXE [file join $WORK_DIR "x11vnc" "x11vnc"]
  148. if {![file isfile $WORK_X11VNC_EXE]} {
  149. puts "ERROR: Can't find packaged x11vnc!"
  150. puts "at $WORK_X11VNC_EXE"
  151. } else {
  152. exec chmod u+x $WORK_X11VNC_EXE
  153. }
  154. }
  155. # Initialize VNC environment for Windows.
  156. proc init_windows {} {
  157. variable VNC_APP_NAME "TightVNC"
  158. variable VNC_APP_VERSION "2.8.5"
  159. variable VNC_APP_LICENSE "GPLv2"
  160. variable SSH_APP_NAME "OpenSSH"
  161. variable SSH_APP_VERSION "???"
  162. variable SSH_APP_LICENSE "BSD"
  163. variable SSH_APP_PROVIDED 0
  164. variable USE_PROVIDED_SSH_APP 0
  165. # Prepare work directory.
  166. variable WORK_DIR [file join $::support::TEMP_DIR "work"]
  167. file copy [file join $::support::DATA_DIR "windows"] $WORK_DIR
  168. # Get path to tvnserver.exe in work directory.
  169. variable WORK_TIGHTVNC_EXE [file join $WORK_DIR "tightvnc" "tvnserver.exe"]
  170. if {![file isfile $WORK_TIGHTVNC_EXE]} {
  171. puts "ERROR: Can't find packaged tvnserver.exe!"
  172. puts "at $WORK_TIGHTVNC_EXE"
  173. }
  174. # Get path to running.bat in work directory.
  175. variable WORK_RUNNING_EXE [file join $WORK_DIR "running.bat"]
  176. if {![file isfile $WORK_RUNNING_EXE]} {
  177. puts "ERROR: Can't find packaged running.bat!"
  178. puts "at $WORK_RUNNING_EXE"
  179. }
  180. # Get path to ssh.exe in work directory.
  181. variable WORK_SSH_EXE [file join $WORK_DIR "openssh" "bin" "ssh.exe"]
  182. if {![file isfile $WORK_SSH_EXE]} {
  183. puts "ERROR: Can't find packaged ssh.exe!"
  184. puts "at $WORK_SSH_EXE"
  185. } else {
  186. # fetch version of packaged ssh
  187. if {[catch {exec [file nativename $WORK_SSH_EXE] -V 2>@1} result]} {
  188. puts "ERROR: Can't fetch version of packaged ssh.exe!"
  189. puts $::errorInfo
  190. } else {
  191. if {$result != "" && [string first "OpenSSH_" $result] == 0} {
  192. set version [lindex [split $result ","] 0]
  193. set SSH_APP_VERSION [string range $version 8 end]
  194. set SSH_APP_PROVIDED 1
  195. set USE_PROVIDED_SSH_APP 1
  196. } else {
  197. puts "ERROR: Can't fetch version of packaged ssh.exe!"
  198. puts "> from response: $result"
  199. }
  200. }
  201. }
  202. }
  203. # Test, if VNC session is currently running.
  204. proc is_running {} {
  205. if {[::support::utils::is_darwin]} {
  206. return [is_running_darwin]
  207. }
  208. if {[::support::utils::is_linux]} {
  209. return [is_running_linux]
  210. }
  211. if {[::support::utils::is_windows]} {
  212. return [is_running_windows]
  213. }
  214. return 0
  215. }
  216. # Test for Mac OS X, if VNC session is currently running.
  217. proc is_running_darwin {} {
  218. variable PIDS
  219. # Check process ids.
  220. if {[llength $PIDS] < 1} {
  221. return 0
  222. }
  223. foreach processId $PIDS {
  224. # Check main process.
  225. if {![::support::utils::process_is_running_darwin $processId]} {
  226. return 0
  227. }
  228. # Check child processes.
  229. foreach childProcessId [::support::utils::process_children_darwin $processId] {
  230. if {![::support::utils::process_is_running $childProcessId]} {
  231. return 0
  232. }
  233. }
  234. }
  235. return 1
  236. }
  237. # Test for Linux, if VNC session is currently running.
  238. proc is_running_linux {} {
  239. variable PIDS
  240. # Check process ids.
  241. if {[llength $PIDS] < 1} {
  242. return 0
  243. }
  244. foreach processId $PIDS {
  245. # Check main process.
  246. if {![::support::utils::process_is_running_linux $processId]} {
  247. return 0
  248. }
  249. # Check child processes.
  250. foreach childProcessId [::support::utils::process_children_linux $processId] {
  251. if {![::support::utils::process_is_running_linux $childProcessId]} {
  252. return 0
  253. }
  254. }
  255. }
  256. return 1
  257. }
  258. # Test for Windows, if VNC session is currently running.
  259. proc is_running_windows {} {
  260. variable PIDS
  261. variable WORK_RUNNING_EXE
  262. # Check for a running tvnserver.exe.
  263. if {[catch {exec $WORK_RUNNING_EXE "tvnserver.exe"} result]} {
  264. puts "Can't check if TightVNC is running!"
  265. puts $::errorInfo
  266. return 0
  267. }
  268. set result [string trim $result]
  269. if {$result != "1"} {
  270. puts "TightVNC is not running anymore ($result)."
  271. return 0
  272. }
  273. return 1
  274. }
  275. # Start VNC session.
  276. proc start {} {
  277. if {[::support::utils::is_darwin]} {
  278. return [start_darwin]
  279. }
  280. if {[::support::utils::is_linux]} {
  281. return [start_linux]
  282. }
  283. if {[::support::utils::is_windows]} {
  284. return [start_windows]
  285. }
  286. error "VNC is not supported for the operating system!"
  287. }
  288. # Start VNC session for Mac OS X.
  289. proc start_darwin {} {
  290. variable PIDS
  291. variable LOG_FILE
  292. variable VNC_EXE
  293. variable VNC_HOST
  294. variable VNC_PORT
  295. variable VNC_PARAMETERS
  296. variable SSH_ENABLED
  297. variable WORK_OSXVNC_EXE
  298. variable USE_PROVIDED_VNC_APP
  299. # Stop currently running VNC session.
  300. if {[is_running_darwin]} {
  301. stop_darwin
  302. }
  303. puts [string repeat "-" 50]
  304. puts "Start VNC session for Mac OS X."
  305. set commands {}
  306. # Get command for SSH tunneling.
  307. if {$SSH_ENABLED != 1} {
  308. set vncHost $VNC_HOST
  309. } else {
  310. set vncHost "127.0.0.1"
  311. lappend commands [join [openssh_prepare] " "]
  312. }
  313. # Detect path to OSXvnc-server application.
  314. if {$USE_PROVIDED_VNC_APP == 1} {
  315. set vncExe $WORK_OSXVNC_EXE
  316. } else {
  317. set vncExe $VNC_EXE
  318. }
  319. if {$vncExe == "" || ![file isfile $vncExe] || ![file executable $vncExe]} {
  320. error "Can't find OSXvnc-server application!"
  321. }
  322. # Build command for VNC connection.
  323. lappend commands [format "%s -connectHost %s -connectPort %s -localhost %s" $vncExe $vncHost $VNC_PORT $VNC_PARAMETERS ]
  324. # Create VNC command.
  325. #set command [join $commands "; "]
  326. set command [join $commands " && "]
  327. puts $command
  328. # Execute VNC command.
  329. set PIDS [exec bash << $command >>& $LOG_FILE &]
  330. #set PIDS [exec bash << $command >@ stdout &]
  331. puts "Established VNC connection with process id: $PIDS"
  332. puts [string repeat "-" 50]
  333. return 1
  334. }
  335. # Start VNC session for Linux.
  336. proc start_linux {} {
  337. variable PIDS
  338. variable LOG_FILE
  339. variable VNC_EXE
  340. variable VNC_HOST
  341. variable VNC_PORT
  342. variable VNC_PARAMETERS
  343. variable SSH_ENABLED
  344. variable WORK_X11VNC_EXE
  345. variable USE_PROVIDED_VNC_APP
  346. # Stop currently running VNC session.
  347. if {[is_running_linux]} {
  348. stop_linux
  349. }
  350. puts [string repeat "-" 50]
  351. puts "Start VNC session for Linux."
  352. set commands {}
  353. # Get command for SSH tunneling.
  354. if {$SSH_ENABLED != 1} {
  355. set vncHost $VNC_HOST
  356. } else {
  357. set vncHost "127.0.0.1"
  358. lappend commands [join [openssh_prepare] " "]
  359. }
  360. # Detect path to x11vnc application.
  361. if {$USE_PROVIDED_VNC_APP == 1} {
  362. set vncExe $WORK_X11VNC_EXE
  363. } else {
  364. set vncExe $VNC_EXE
  365. }
  366. if {$vncExe == "" || ![file isfile $vncExe] || ![file executable $vncExe]} {
  367. error "Can't find x11vnc application!"
  368. }
  369. # Build command for VNC connection.
  370. lappend commands [format "%s -connect_or_exit %s:%s -nopw -nocmds -nevershared -rfbport 0 %s" $vncExe $vncHost $VNC_PORT $VNC_PARAMETERS]
  371. # Create VNC command.
  372. #set command [join $commands "; "]
  373. set command [join $commands " && "]
  374. puts $command
  375. # Execute VNC command.
  376. set PIDS [exec bash << $command >>& $LOG_FILE &]
  377. #set PIDS [exec bash << $command >@ stdout &]
  378. puts "Established VNC connection with process id: $PIDS"
  379. puts [string repeat "-" 50]
  380. return 1
  381. }
  382. # Start VNC session for Windows.
  383. proc start_windows {} {
  384. variable PIDS
  385. variable VNC_EXE
  386. variable VNC_HOST
  387. variable VNC_PORT
  388. #variable VNC_PARAMETERS
  389. variable SSH_ENABLED
  390. variable WORK_TIGHTVNC_EXE
  391. variable USE_PROVIDED_VNC_APP
  392. # Stop currently running VNC session.
  393. if {[is_running_windows]} {
  394. stop_windows
  395. }
  396. puts [string repeat "-" 50]
  397. puts "Start VNC session for Windows."
  398. # Detect path to TightVNC application.
  399. if {$USE_PROVIDED_VNC_APP == 1} {
  400. set vncExe $WORK_TIGHTVNC_EXE
  401. } else {
  402. set vncExe $VNC_EXE
  403. }
  404. if {$vncExe == "" || ![file isfile $vncExe] || ![file executable $vncExe]} {
  405. error "Can't find TightVNC application!"
  406. }
  407. set vncExe [file nativename $vncExe]
  408. # Setup windows registry for TightVNC.
  409. set registryKey "HKEY_CURRENT_USER\\SOFTWARE\\TightVNC\\Server"
  410. registry set $registryKey "AcceptHttpConnections" 0 dword
  411. registry set $registryKey "AcceptRfbConnections" 0 dword
  412. registry set $registryKey "AllowLoopback" 1 dword
  413. #registry set $registryKey "GrabTransparentWindows" 0 dword
  414. registry set $registryKey "RemoveWallpaper" 1 dword
  415. registry set $registryKey "UseVncAuthentication" 0 dword
  416. #registry broadcast "Environment"
  417. # Start TightVNC.
  418. puts [string repeat "-" 50]
  419. puts "Start TightVNC"
  420. puts "$vncExe -run"
  421. if {[catch {exec $vncExe "-run" &}]} {
  422. puts "Can't start TightVNC!"
  423. puts $::errorInfo
  424. return 0
  425. }
  426. # Configure TightVNC.
  427. puts [string repeat "-" 50]
  428. puts "Configure TightVNC"
  429. puts "$vncExe -controlapp -shareprimary"
  430. if {[catch {exec $vncExe "-controlapp" "-shareprimary"}]} {
  431. puts "Can't configure TightVNC!"
  432. puts $::errorInfo
  433. stop_windows
  434. return 0
  435. }
  436. # Init SSH tunnel.
  437. if {$SSH_ENABLED != 1} {
  438. set vncHost $VNC_HOST
  439. } else {
  440. set vncHost "127.0.0.1"
  441. if {[catch {openssh_prepare} sshCommand]} {
  442. puts "Can't initialize OpenSSH!"
  443. puts $::errorInfo
  444. stop_windows
  445. return 0
  446. }
  447. puts [string repeat "-" 50]
  448. puts "Create SSH tunnel"
  449. puts [join $sshCommand " "]
  450. if {[catch {exec {*}$sshCommand &} PIDS]} {
  451. puts "Can't start OpenSSH!"
  452. puts $::errorInfo
  453. stop_windows
  454. return 0
  455. }
  456. puts "Started OpenSSH with process id: $PIDS"
  457. # Wait until SSH tunnel is available.
  458. set i 0
  459. while {1 < 2} {
  460. puts "Waiting for SSH tunnel to become available."
  461. after 1000
  462. if {[tunnel_is_loaded_windows]} {
  463. puts "SSH tunnel is established."
  464. break
  465. }
  466. incr i
  467. if {$i > 15} {
  468. puts "Waited too long for the SSH tunnel to be established."
  469. stop_windows
  470. return 0
  471. }
  472. }
  473. }
  474. # Connect TightVNC.
  475. set target [format "%s:%s" $vncHost $VNC_PORT]
  476. puts [string repeat "-" 50]
  477. puts "Connect TightVNC"
  478. puts "$vncExe -controlapp -connect $target"
  479. if {[catch {exec $vncExe "-controlapp" "-connect" $target}]} {
  480. puts "Can't connect TightVNC!"
  481. puts $::errorInfo
  482. stop_windows
  483. return 0
  484. }
  485. puts "Established VNC connection"
  486. puts [string repeat "-" 50]
  487. return 1
  488. }
  489. # Stop VNC session.
  490. proc stop {} {
  491. variable PIDS
  492. if {[::support::utils::is_darwin]} {
  493. stop_darwin
  494. } elseif {[::support::utils::is_linux]} {
  495. stop_linux
  496. } elseif {[::support::utils::is_windows]} {
  497. stop_windows
  498. }
  499. set PIDS {}
  500. return 0
  501. }
  502. # Stop VNC session for Mac OS X.
  503. proc stop_darwin {} {
  504. variable PIDS
  505. puts [string repeat "-" 50]
  506. puts "Stop VNC session for Mac OS X."
  507. if {[llength $PIDS] < 1} {
  508. return 0
  509. }
  510. foreach processId $PIDS {
  511. # Kill child processes.
  512. foreach childProcessId [::support::utils::process_children_darwin $processId] {
  513. ::support::utils::process_kill_darwin $childProcessId
  514. }
  515. # Kill main process.
  516. ::support::utils::process_kill_darwin $processId
  517. }
  518. return 1
  519. }
  520. # Stop VNC session for Linux.
  521. proc stop_linux {} {
  522. variable PIDS
  523. puts [string repeat "-" 50]
  524. puts "Stop VNC session for Linux."
  525. if {[llength $PIDS] < 1} {
  526. return 0
  527. }
  528. foreach processId $PIDS {
  529. # Kill child processes.
  530. foreach childProcessId [::support::utils::process_children_linux $processId] {
  531. ::support::utils::process_kill_linux $childProcessId
  532. }
  533. # Kill main process.
  534. ::support::utils::process_kill_linux $processId
  535. }
  536. return 1
  537. }
  538. # Stop VNC session for Windows.
  539. proc stop_windows {} {
  540. variable PIDS
  541. variable VNC_EXE
  542. variable WORK_TIGHTVNC_EXE
  543. variable USE_PROVIDED_VNC_APP
  544. puts [string repeat "-" 50]
  545. puts "Stop VNC session for Windows."
  546. # Detect path to TightVNC application.
  547. if {$USE_PROVIDED_VNC_APP == 1} {
  548. set vncExe $WORK_TIGHTVNC_EXE
  549. } else {
  550. set vncExe $VNC_EXE
  551. }
  552. if {$vncExe == "" || ![file isfile $vncExe] || ![file executable $vncExe]} {
  553. error "Can't find TightVNC application!"
  554. }
  555. set vncExe [file nativename $vncExe]
  556. # Disconnect TightVNC.
  557. puts [string repeat "-" 50]
  558. puts "Disconnect TightVNC"
  559. puts "$vncExe -controlapp -disconnectall"
  560. if {[catch {exec $vncExe -controlapp -disconnectall}]} {
  561. puts "Can't disconnect TightVNC!"
  562. puts $::errorInfo
  563. return 0
  564. }
  565. # Shutdown TightVNC.
  566. puts [string repeat "-" 50]
  567. puts "Shutdown TightVNC"
  568. puts "$vncExe -controlapp -shutdown"
  569. if {[catch {exec $vncExe -controlapp -shutdown}]} {
  570. puts "Can't shutdown TightVNC!"
  571. puts $::errorInfo
  572. return 0
  573. }
  574. return 1
  575. }
  576. # Prepare SSH tunneling via OpenSSH and return the command for execution.
  577. proc openssh_prepare {} {
  578. variable WORK_DIR
  579. variable WORK_SSH_EXE
  580. variable VNC_HOST
  581. variable VNC_PORT
  582. variable SSH_EXE
  583. variable SSH_PORT
  584. variable SSH_USER
  585. variable SSH_KEY
  586. variable SSH_KEY_PROVIDED
  587. variable USE_PROVIDED_SSH_KEY
  588. variable USE_PROVIDED_SSH_APP
  589. # Copy ssh key into work directory.
  590. set sshKey [file join $WORK_DIR "ssh.key"]
  591. if {$SSH_KEY_PROVIDED == 1 && $USE_PROVIDED_SSH_KEY == 1} {
  592. file copy -force [file join $::support::DATA_DIR "ssh.key"] $sshKey
  593. } elseif {$SSH_KEY != "" && [file isfile $SSH_KEY]} {
  594. file copy -force $SSH_KEY $sshKey
  595. }
  596. # Set permissions on ssh.key on non Windows systems.
  597. if {![::support::utils::is_windows] && $sshKey!= "" && [file exists $sshKey]} {
  598. exec chmod 600 $sshKey
  599. }
  600. set command {}
  601. # Set ssh application.
  602. if {$USE_PROVIDED_SSH_APP == 1} {
  603. lappend command [file nativename $WORK_SSH_EXE]
  604. } elseif {$SSH_EXE != "" && [file isfile $SSH_EXE]} {
  605. lappend command [file nativename $SSH_EXE]
  606. } else {
  607. error "Can't find ssh!"
  608. }
  609. # Set tunneling options.
  610. lappend command "-L"
  611. lappend command [format "%s:127.0.0.1:%s" $VNC_PORT $VNC_PORT]
  612. lappend command "-f"
  613. lappend command "-o"
  614. lappend command "ExitOnForwardFailure=yes"
  615. # Set SSH port.
  616. lappend command "-p"
  617. lappend command $SSH_PORT
  618. # Set compression.
  619. lappend command "-C"
  620. # Disable X11 forwarding.
  621. lappend command "-x"
  622. # Set authentication via keyfile.
  623. if {$sshKey != "" && [file isfile $sshKey]} {
  624. lappend command "-i"
  625. lappend command [file nativename $sshKey]
  626. lappend command "-o"
  627. lappend command "PreferredAuthentications=publickey"
  628. } else {
  629. error "No ssh keyfile was specified!"
  630. }
  631. # Disable host checks
  632. lappend command "-o"
  633. lappend command "StrictHostKeyChecking=no"
  634. lappend command "-o"
  635. lappend command "GlobalKnownHostsFile=/dev/null"
  636. lappend command "-o"
  637. lappend command "UserKnownHostsFile=/dev/null"
  638. lappend command "-o"
  639. lappend command "CheckHostIP=no"
  640. # Set user and hostname.
  641. lappend command [format "%s@%s" $SSH_USER $VNC_HOST]
  642. # Set remote command.
  643. lappend command "sleep"
  644. lappend command "15"
  645. return $command
  646. }
  647. # Test for Windows systems, if a SSH tunnel is available.
  648. proc tunnel_is_loaded_windows {} {
  649. variable VNC_PORT
  650. set expectedLocalAddress "127.0.0.1:$VNC_PORT"
  651. # fetch available connections through netstat.exe
  652. if {[catch {exec "netstat.exe" "-a" "-n" "-p" "TCP"} result]} {
  653. puts "Can't test if Plink is loaded!"
  654. puts $::errorInfo
  655. return 0
  656. }
  657. # parse lines from the response by netstat.exe
  658. set lines [split [string trim $result] "\n"]
  659. foreach line $lines {
  660. set line [string trim $line]
  661. #puts "> NETSTAT: $line"
  662. # replace double spaces with single spaces
  663. set pos [string first " " $line]
  664. while {$pos > -1} {
  665. set line [string replace $line $pos [expr {$pos + 1}] " "]
  666. set pos [string first " " $line]
  667. }
  668. # split netstat result into separate values
  669. set values [split $line " "]
  670. if {[llength $values] < 2} {
  671. continue
  672. }
  673. # make sure, that the lines starts with TCP
  674. set protocol [string toupper [lindex $values 0]]
  675. if {$protocol != "TCP"} {
  676. continue
  677. }
  678. # the ssh tunnel is available, if its local address is present right after TCP
  679. set localAddress [string toupper [lindex $values 1]]
  680. if {$localAddress == $expectedLocalAddress} {
  681. return 1
  682. }
  683. }
  684. return 0
  685. }
  686. # Validate session settings.
  687. proc validate {} {
  688. set errors {}
  689. # VNC host address needs to be available.
  690. variable VNC_HOST
  691. if {$VNC_HOST == ""} {
  692. lappend errors [_ "An invalid address was specified."]
  693. }
  694. # VNC port number needs to be available.
  695. variable VNC_PORT
  696. if {![string is integer -strict $VNC_PORT] || $VNC_PORT < 1 || $VNC_PORT > 65535} {
  697. lappend errors [_ "An invalid port number was specified."]
  698. }
  699. # Custom VNC application needs to be available.
  700. variable USE_PROVIDED_VNC_APP
  701. if {$USE_PROVIDED_VNC_APP != 1} {
  702. variable VNC_EXE
  703. if {$VNC_EXE == "" || ![file isfile $VNC_EXE] || ![file executable $VNC_EXE]} {
  704. lappend errors [_ "An invalid VNC application was specified."]
  705. }
  706. }
  707. # Validate SSH settings, if SSH is enabled.
  708. variable SSH_ENABLED
  709. if {$SSH_ENABLED == 1} {
  710. # SSH application needs to be available.
  711. variable USE_PROVIDED_SSH_APP
  712. if {$USE_PROVIDED_SSH_APP == 1} {
  713. # Provided SSH application needs to be available.
  714. variable SSH_APP_PROVIDED
  715. if {$SSH_APP_PROVIDED != 1} {
  716. lappend errors [_ "There is no provided SSH application available."]
  717. }
  718. } else {
  719. # Custom SSH application needs to be available.
  720. variable SSH_EXE
  721. if {$SSH_EXE == "" || ![file isfile $SSH_EXE] || ![file executable $SSH_EXE]} {
  722. lappend errors [_ "An invalid SSH application was specified."]
  723. }
  724. }
  725. # SSH user needs to be available.
  726. variable SSH_USER
  727. if {$SSH_USER == ""} {
  728. lappend errors [_ "An invalid SSH user was specified."]
  729. }
  730. # SSH port number needs to be available.
  731. variable SSH_PORT
  732. if {![string is integer -strict $SSH_PORT] || $SSH_PORT < 1 || $SSH_PORT > 65535} {
  733. lappend errors [_ "An invalid SSH port number was specified."]
  734. }
  735. # SSH key needs to be available.
  736. variable USE_PROVIDED_SSH_KEY
  737. if {$USE_PROVIDED_SSH_KEY == 1} {
  738. # Provided SSH key needs to be available.
  739. variable SSH_KEY_PROVIDED
  740. if {$SSH_KEY_PROVIDED != 1} {
  741. lappend errors [_ "There is no provided SSH key available."]
  742. }
  743. } else {
  744. # Custom SSH key needs to be available.
  745. variable SSH_KEY
  746. if {$SSH_KEY == "" || ![file isfile $SSH_KEY]} {
  747. lappend errors [_ "An invalid SSH key was specified."]
  748. }
  749. }
  750. }
  751. return $errors
  752. }
  753. }