[英]How can I execute an external commands in C/Linux without using system, popen, fork, exec?
[英]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.