如何在保留控制台密码提示的同时通过管道调用SSH
自定义
git-remote-<transport>助手的跨平台管道与SSH密码提示问题 我正在编写自定义git-remote-<transport>助手,该助手可在必要时使用自研传输协议,也能回退到基于Smart Protocol的标准SSH协议。这意味着需要实现Git的git_connect方法,调用SSH建立连接并执行远程git-upload-pack或git-receive-pack命令,同时将Git进程的stdin/stdout管道传输至子SSH进程,流程如下:
+-----------------------------------------------------------+ | Process: git Handles: writer, reader | +--------------------------------------------- | ----- ^ ---+ (pipe) (pipe) +--------------------------------------------- v ----- | ---+ | Process: git-remote-mytransport Handles: stdin , stdout | | \ / | | (custom logic) | | / \ | | writer, reader | +--------------------------------------------- | ----- ^ ---+ (pipe) (pipe) +--------------------------------------------- v ----- | ---+ | Process: ssh Handles: stdin , stdout | | \ / | | TCP socket | +------------------------------------------------- ^ -------+ | v Remote SSH Host
仅处理stdin/stdout句柄的实现很简单,但SSH的密码提示功能会因盲目重定向管道句柄而失效。
当前实现参考了相关代码,Windows测试命令如下:
go build -o .\bin\git-remote-mytransport .\git-remote-mytransport.go SET PATH=%CD%\bin;%PATH% git clone mytransport://dummy
当前实现能正常弹出密码提示,但Git与SSH的stdin/stdout管道传输异常;若直接传递os.Stdin和os.Stdout启动SSH,管道正常但密码提示失效。
Windows的控制台架构较为复杂,经过一天研究仍未实现Git到SSH的可用管道且不破坏密码提示。需要在Windows/Linux/macOS多平台解决该问题,当前用Golang开发,也可接受基于原生API的C/C++方案以便移植。
2023年7月3日更新:参考Microsoft ConPTY文章及示例代码后尝试如下方案,但仍无法工作:
HANDLE hLocalReader, hLocalWriter, hRemoteReader, hRemoteWriter; CreatePipe(&hLocalReader, &hRemoteWriter, NULL, 0); CreatePipe(&hRemoteReader, &hLocalWriter, NULL, 0); HPCON hPC; CreatePseudoConsole(consoleSize, hRemoteReader, hRemoteWriter, 0, &hPC); HANDLE hConIn = CreateFile("CONIN$", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); HANDLE hConOut = CreateFile("CONOUT$", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); DWORD consoleMode; GetConsoleMode(hConOut, &consoleMode); SetConsoleMode(hConOut, consoleMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); // on another thread, stream hConIn data to hLocalWriter // on another thread, stream hLocalReader data to hConOut HANDLE handles[3]; HANDLE handles[0] = GetStdHandle(STD_INPUT_HANDLE); HANDLE handles[1] = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE handles[2] = GetStdHandle(STD_ERROR_HANDLE); pStartupInfo->hStdInput = handles[0]; pStartupInfo->hStdOutput = handles[1]; pStartupInfo->hStdError = handles[2]; UpdateProcThreadAttribute(pStartupInfo->lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL); UpdateProcThreadAttribute(pStartupInfo->lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, hPC, sizeof(HPCON), NULL, NULL); CreateProcess( szCommand, // Command name szArgs, // Command arguments NULL, // Process handle not inheritable NULL, // Thread handle not inheritable TRUE, // Inherit handles EXTENDED_STARTUPINFO_PRESENT, // Creation flags NULL, // Use parent's environment block NULL, // Use parent's starting directory &startupInfo.StartupInfo, // Pointer to STARTUPINFO &piClient); // Pointer to PROCESS_INFORMATION
内容的提问来源于stack exchange,提问作者Rix
相关产品推荐
相关产品推荐

