免费做网站推荐,网站推广意识薄弱,网站建设与规划方案书,服务器做jsp网站教程视频教程在工作中遇到一段代码#xff0c;通过SSH_ASKPASS全局变量实现了ssh登录远程IP时的密码输入#xff0c;chatgpt搜索了一下#xff0c;其解释大致如下所示#xff1a;
SSH_ASKPASS 是一个环境变量#xff0c;它在 SSH 客户端需要用户输入密码时起作用。当 SSH 客户端检测到…在工作中遇到一段代码通过SSH_ASKPASS全局变量实现了ssh登录远程IP时的密码输入chatgpt搜索了一下其解释大致如下所示
SSH_ASKPASS 是一个环境变量它在 SSH 客户端需要用户输入密码时起作用。当 SSH 客户端检测到需要密码时它会首先检查环境变量 SSH_ASKPASS 是否已设置。如果设置了 SSH_ASKPASS那么 SSH 客户端会调用指定的程序来获取密码而不是直接在终端中提示用户输入密码。
具体来说SSH 客户端的工作流程如下
客户端发起 SSH 连接请求。当服务器需要验证客户端身份时服务器向客户端发送一个密码提示请求。客户端检查 SSH_ASKPASS 环境变量。如果 SSH_ASKPASS 已设置则客户端调用指定的程序来获取密码。获取到密码后客户端将密码传递给 SSH 客户端进行身份验证。如果验证成功SSH 连接建立成功否则连接失败。
通过设置 SSH_ASKPASS 环境变量用户可以自定义一个程序来自动化密码输入过程从而实现无需人工干预的 SSH 连接过程。这在自动化脚本或程序中特别有用可以避免需要用户手动输入密码。
不过百度和谷歌却没搜索到人定义的关键信息来确认这点。让chatgpt帮我把ssh源码中的SSH_ASKPASS部分调用代码展示出来可能理解有问题每次都答非所问。自己下载了一份ssh源码简单的用grep SSH_ASKPASS . -rns指令检索到应该是如下的代码中实现的调用
struct notifier_ctx *
notify_start(int force_askpass, const char *fmt, ...)
{va_list args;char *prompt NULL;pid_t pid -1;void (*osigchld)(int) NULL;const char *askpass, *s; struct notifier_ctx *ret NULL;va_start(args, fmt);xvasprintf(prompt, fmt, args);va_end(args);if (fflush(NULL) ! 0)error_f(fflush: %s, strerror(errno));if (!force_askpass isatty(STDERR_FILENO)) {writemsg(prompt);goto out_ctx;}if ((askpass getenv(SSH_ASKPASS)) NULL)askpass _PATH_SSH_ASKPASS_DEFAULT;if (*askpass \0) {debug3_f(cannot notify: no askpass);goto out;}if (getenv(DISPLAY) NULL getenv(WAYLAND_DISPLAY) NULL ((s getenv(SSH_ASKPASS_REQUIRE_ENV)) NULL ||strcmp(s, force) ! 0)) {debug3_f(cannot notify: no display);goto out;}osigchld ssh_signal(SIGCHLD, SIG_DFL);if ((pid fork()) -1) { error_f(fork: %s, strerror(errno));ssh_signal(SIGCHLD, osigchld);free(prompt);return NULL;}if (pid 0) {if (stdfd_devnull(1, 1, 0) -1)fatal_f(stdfd_devnull failed);closefrom(STDERR_FILENO 1);setenv(SSH_ASKPASS_PROMPT, none, 1); /* hint to UI */execlp(askpass, askpass, prompt, (char *)NULL);error_f(exec(%s): %s, askpass, strerror(errno));_exit(1);/* NOTREACHED */}out_ctx:if ((ret calloc(1, sizeof(*ret))) NULL) {if (pid ! -1)kill(pid, SIGTERM);fatal_f(calloc failed);}ret-pid pid; ret-osigchld osigchld;out:free(prompt);return ret;
}其中的关键调用指令就是execlp(askpass, askpass, prompt, (char *)NULL);
参数释义第一个和第二个都是SSH_ASKPASS文件路径prompt是提示词也就是“please enter 192.68.1.10 password:”之类的打印信息第四个参数无什么含义不解释。
上面代码execlp调用SSH_ASKPASS后无任何返回值判定和处理那密码是怎么实现自动输入到stdin输入的呢
看源码中execlp是在fork的子进程中执行的执行前其通过stdfd_devnull(1, 1, 0)关闭了子进程的stdout、stderr和stdin的流再使用closefrom(STDERR_FILENO 1)关闭了大于STDERR_FILENO的所有流个人猜测这样可以实现子进程的密码输出流作为ssh密码录入的stdin流。但是chatgpt的解释是关闭后SSH_ASKPASS中任意print不会输出到任何地方有点困惑。
所以如果我们有需求ssh登录时期望自动输入密码可以使用这个功能来自动后台运行只需要在运行前指定系统的SSH_ASKPASS全局变量即可。下面写一个简单的SSH_ASKPASS功能函数。
#!/usr/bin/python3
import sysif password in sys.argv[1]:print(123456)