繁体   English   中英

如何在 C 中 fork&exec bash shell?

[英]How can I fork&exec bash shell in C?

尝试在 C 中创建一个新的 bash shell 并将其提供给用户,这是我的代码:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    
    char* secretpass = "password";
    char password[50];

    printf("%s", "Password: ");
    fgets(password, 50, stdin);
    password[strcspn(password, "\n")] = 0;

    if (!strcmp(password, secretpass)){
        pid_t pid = fork();
        if (pid == 0){
            execl("/bin/bash", "bash", NULL);
        }
    }
    return 0;
}

运行代码(ELF)后,我在ps获得了一个新的 bash shell,但它不是我的 shell,因为echo $$带来了第一个 shell,我该怎么做才能让新 shell 显示出来? 内核模块会有帮助吗?

编辑:

编辑了我的代码以获得更多帮助,/dev/chardev 是一个启动过程的字符设备,驱动程序也是 0666 (.rw.rw.rw.) 每个人都可以写的, system(cmd)在那里说控制台没有权限,即使我在 execve 之后自己执行命令。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>

#define MAX 50
#define USERNAME 2

int main(int argc, char const *argv[])
{


    // Declare variables.
    const char* username = argv[USERNAME];
    char* password = (char*)calloc(MAX, sizeof(char));
    char* cmd = (char*)calloc(5 * MAX, sizeof(char));
    char* secretpass = "password";


    printf("%s", "Password: ");
    fgets(password, MAX, stdin);
    password[strcspn(password, "\n")] = 0;

    
    if (!strcmp(password, secretpass)){
        int err;
        
        struct passwd* pw_user = getpwnam(username);
        //printf("-%s-%s-%d-%d-%s-%s-%s-\n", pw_user->pw_name, pw_user->pw_passwd,
         //pw_user->pw_uid, pw_user->pw_gid, pw_user->pw_gecos,
          //pw_user->pw_dir, pw_user->pw_shell);
        

        if ( (err = fchown(0, pw_user->pw_uid, pw_user->pw_gid) ) != 0)
            printf("%s %d\n", "fchown error", err);

        if ( (err = setpgid(0, 0) ) != 0)
            printf("%s %d\n", "setpgid error", err);

        if ( (err = tcsetpgrp(0, getpid()) ) != 0)
            printf("%s %d\n", "tcsetpgrp error", err);

        if ( (err = chdir(pw_user->pw_dir) ) != 0)
            printf("%s %d\n", "chdir error", err);

        if ( (err = setgid(pw_user->pw_gid) ) != 0)
            printf("%s %d\n", "setgid error", err);

        if ( (err = setuid(pw_user->pw_uid) ) != 0)
            printf("%s %d\n", "setuid error", err);



        sprintf(cmd, "%s \"%d %d %d\" %s", "echo", pw_user->pw_uid, pw_user->pw_gid, getpid(), "> /dev/chardev");
        system(cmd);

        const char *args[] = {"bash", "--rcfile", "/etc/bashrc", NULL};

        char LOGNAME[MAX];
        char HOME[MAX];
        char USER[MAX];
        sprintf(LOGNAME, "%s%s", "LOGNAME=", pw_user->pw_name);
        sprintf(HOME, "%s%s", "HOME=",pw_user->pw_dir);
        sprintf(USER, "%s%s", "USER=", pw_user->pw_name);

        const char *env[] = {"SHELL=/bin/bash", LOGNAME, HOME, USER, "IFS= ","PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin", "TTY=tty1", NULL}; /* need to generate these; TTY is passed to you */

        execve("/bin/bash", args, env);

    }
    else
        execl("/bin/login", "login", NULL);


    return 0;
}

总是 setpgid 错误,如果用户名不是 root,也会出现 setuid 和 chdir 错误。

来自评论:您正在尝试编写登录程序。

好的。 这有点多,而且你正在以错误的方式处理这件事。 我们根本不想分叉。 init担心等待。 无论如何,我们可以在这里写一个长序列:

    int targetuid = ... ; /* You need a strategy for getting this */
    int targetgid = ... ; /* You need a strategy for getting this */
    const char *homdir = ... ; /* You need a strategy for getting this */
    if (!strcmp(password, secretpass)){
        /* Start up the user's shell */
        fchown(0, targetuid, targetgid);
        setpgid(0, 0);
        tcsetpgrp(0, getpid());
        chdir(homedir);
        setgid(targetgid);
        setuid(targetuid);
        const char *args[] = {"-bash", NULL};
        const char *env[] = {"SHELL=/bin/bash", "LOGNAME=...", "HOME=...", "USER=...", IFS="...", PATH=/bin:/usr/bin", "TERM=...", NULL }; /* need to generate these; TERM is passed to you */
        execve("/bin/bash", args, env);
    }

这涉及很多,我实际上不推荐这样做,除非你真的必须这样做。 当我尝试这个时,我学到了很多东西,但花了很长时间才让它正常工作。

特别注意事项: 1) 登录成功后,tty 设备需要归用户所有。 因此fchown(0, ...)调用将所有权授予用户。 2) chdir()首先是传统的; 如果你愿意,你可以颠倒顺序,但我不明白为什么。 3) 使用 argv0 中的前导 - 启动 shell 告诉 shell 它是一个登录 shell。 检查ps -f ,您可以看到这一点。

我拿起你的新代码; 它实际上看起来很不错。 我能发现的唯一错误是我自己的; 变量是TERM而不是TTY (现在在我上面的示例中已更正),获取其值的最佳位置是getenv() 在运行你的代码时,我只需要做一个更正; 那是把-bash放回去。 它吐出的唯一错误是关于chardev 什么是chardev

我猜你的失败根本不在这段代码中,而是在你的内核中。

来自聊天的信息:OP 有一个带有自定义/dev/chardev的自定义内核; 我无法解释失败,因为代码对我有用。 内核可能有也可能没有其他更改。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM