You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C语言与Shell交互?含SSH带密码执行命令需求

C语言实现带密码的SSH命令执行方法

你遇到的问题本质是ssh的密码输入是直接和终端(TTY)交互,而非通过标准输入流,所以popen、普通管道这类仅处理标准IO的方法无法捕获密码提示符并输入密码。下面是两种可靠的解决方案:

方法1:使用libssh(纯C SSH协议库)

这是最推荐的方案,直接通过SSH协议和目标主机通信,不需要依赖shell或模拟终端,安全性和可控性更高。

步骤示例:

  1. 先安装libssh开发包(比如apt install libssh-dev或yum install libssh-devel)
  2. 编写C代码实现连接、认证、执行命令:
#include <libssh/libssh.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    ssh_session my_ssh_session;
    int rc;
    char *password = "your_password"; // 注意:实际使用中不要硬编码,建议从安全渠道读取
    char *command = "ls";
    char buffer[256];
    int nbytes;

    // 初始化SSH会话
    my_ssh_session = ssh_new();
    if (my_ssh_session == NULL) exit(-1);

    // 设置连接参数
    ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "192.168.1.1");
    ssh_options_set(my_ssh_session, SSH_OPTIONS_USER, "root");

    // 连接到服务器
    rc = ssh_connect(my_ssh_session);
    if (rc != SSH_OK) {
        fprintf(stderr, "连接失败: %s\n", ssh_get_error(my_ssh_session));
        ssh_free(my_ssh_session);
        exit(-1);
    }

    // 密码认证
    rc = ssh_userauth_password(my_ssh_session, NULL, password);
    if (rc != SSH_OK) {
        fprintf(stderr, "认证失败: %s\n", ssh_get_error(my_ssh_session));
        ssh_disconnect(my_ssh_session);
        ssh_free(my_ssh_session);
        exit(-1);
    }

    // 执行命令
    ssh_channel channel = ssh_channel_new(my_ssh_session);
    if (channel == NULL) exit(-1);

    rc = ssh_channel_open_session(channel);
    if (rc != SSH_OK) {
        ssh_channel_free(channel);
        exit(-1);
    }

    rc = ssh_channel_request_exec(channel, command);
    if (rc != SSH_OK) {
        ssh_channel_close(channel);
        ssh_channel_free(channel);
        exit(-1);
    }

    // 读取命令输出
    nbytes = ssh_channel_read(channel, buffer, sizeof(buffer)-1, 0);
    while (nbytes > 0) {
        buffer[nbytes] = '\0';
        printf("%s", buffer);
        nbytes = ssh_channel_read(channel, buffer, sizeof(buffer)-1, 0);
    }

    // 清理资源
    ssh_channel_send_eof(channel);
    ssh_channel_close(channel);
    ssh_channel_free(channel);
    ssh_disconnect(my_ssh_session);
    ssh_free(my_ssh_session);

    return 0;
}

编译命令:gcc ssh_test.c -o ssh_test -lssh

方法2:使用libexpect(模拟终端交互)

如果你更倾向于通过调用ssh命令的方式实现,可以用libexpect库,它能模拟终端环境,捕获ssh的密码提示符并自动输入密码。

步骤示例:

  1. 安装libexpect开发包(比如apt install libexpect-dev)
  2. 编写C代码:
#include <expect.h>
#include <stdio.h>

int main() {
    expect_t *exp;
    char *prompt = "password:"; // ssh的密码提示符,可能因系统不同略有差异
    char *password = "your_password";
    char *command = "ssh root@192.168.1.1 ls";
    char buffer[1024];
    int status;

    // 初始化expect会话
    exp = exp_spawnl(command, command, NULL);
    if (exp == NULL) {
        perror("spawn failed");
        return -1;
    }

    // 捕获密码提示符并发送密码
    exp_expectl(exp,
                exp_glob, prompt, exp_send, "%s\n", password,
                exp_end);

    // 读取命令输出
    while (exp_read(exp, buffer, sizeof(buffer)-1) > 0) {
        buffer[strcspn(buffer, "\r")] = '\0'; // 处理换行符
        printf("%s\n", buffer);
    }

    // 等待命令执行完成并获取退出状态
    exp_wait(exp, &status, 0);
    exp_close(exp);

    return WEXITSTATUS(status);
}

编译命令:gcc expect_ssh.c -o expect_ssh -lexpect -lutil

不推荐的临时方案:调用sshpass

如果你只是快速实现,也可以通过popen调用sshpass工具(需要先安装),但这种方式密码可能会暴露在进程列表中,安全性极低,仅适合测试环境:

#include <stdio.h>
#include <stdlib.h>

int main() {
    char cmd[256];
    FILE *fp;
    char buffer[1024];

    snprintf(cmd, sizeof(cmd), "sshpass -p 'your_password' ssh root@192.168.1.1 ls");
    fp = popen(cmd, "r");
    if (fp == NULL) {
        perror("popen failed");
        return -1;
    }

    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        printf("%s", buffer);
    }

    pclose(fp);
    return 0;
}

注意事项

  • 硬编码密码存在严重安全风险,实际应用中建议从环境变量、加密配置文件或安全密钥管理系统读取密码。
  • 优先使用libssh这类原生SSH库,避免依赖外部工具或shell,提升程序的稳定性和安全性。

内容的提问来源于stack exchange,提问作者dustChou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 04:21:23