linux中su命令源码

worktile 其他 259

回复

共3条回复 我来回复
  • worktile的头像
    worktile
    Worktile官方账号
    评论

    Linux系统中,su命令是用于切换用户身份的命令,可以通过查看su命令的源码来了解其具体实现机制。

    su命令的源码位于Linux系统的核心组件之一——Linux核心源码中的/usr/src/linux源码树中。具体位置为:/usr/src/linux/kernel/sys.c。

    在sys.c文件中,定义了su命令所用到的相关函数和数据结构。下面是sys.c文件中与su命令相关的核心函数:

    1. do_setuid()函数:用于将当前进程的有效用户ID设置为指定的用户ID。该函数中会进行用户ID的检查和权限的判断,确保只有特定条件下的用户才能使用su命令切换身份。

    2. do_setgid()函数:类似于do_setuid()函数,用于设置当前进程的有效组ID。

    3. validate_process_creds()函数:用于验证当前进程的身份,确保当前进程有足够的权限执行su命令。

    4. su_main()函数:是su命令的主要入口函数,在这个函数中进行了一系列的身份切换和权限验证操作,最后通过执行shell来启动新的用户会话。

    此外,在sys.c文件中还定义了一些辅助函数,如validate_new_exec()函数,用于验证切换后的执行文件是否有足够的权限进行执行。

    需要注意的是,Linux系统的源码非常庞大且复杂,sys.c文件只是其中的一小部分。如果你需要更加详细的了解su命令的实现细节,可以仔细研究Linux内核源码中与用户身份切换相关的部分。

    总结起来,su命令的源码位于Linux系统的内核源码中的sys.c文件中,通过分析这个文件,可以了解su命令的核心实现机制。但需要注意的是,对于非专业开发人员来说,直接阅读和理解Linux内核源码可能较为困难,建议通过查阅相关文档和参考资料来获取更多信息。

    2年前 0条评论
  • 不及物动词的头像
    不及物动词
    这个人很懒,什么都没有留下~
    评论

    su命令是在Linux操作系统中用于切换用户身份的命令。下面是su命令的源码解析:

    1. su命令的源码位于coreutils软件包中的su.c文件。这个文件定义了su命令主要逻辑的实现。

    2. su.c文件中首先包含了一些必要的头文件,如stdio.h、stdlib.h、unistd.h等。这些头文件提供了在程序中使用的各种函数和宏定义。

    3. 主函数main()是su命令的入口,程序从这里开始执行。在主函数中,首先会解析命令行参数,包括要切换的用户、运行的shell等。然后,检查当前用户的权限,如果用户不是root或者没有root权限,则执行完整的验证过程。这个过程主要包括验证用户密码和执行其他安全检查。

    4. 如果当前用户是root或者验证成功,则会进行切换用户的操作。su命令通过调用setreuid()和setregid()函数实现用户身份的切换。这些函数通过更改实际用户和有效用户ID以及实际组和有效组ID来切换用户身份。

    5. 如果切换用户成功,则会执行指定的shell。su命令会通过execvp()函数执行指定的shell,这个函数会在PATH环境变量指定的目录中搜索可执行文件并执行。如果没有指定shell,则默认执行系统默认的shell。

    总结:
    su命令的源码实现了用户身份切换的逻辑。它会根据当前用户的身份进行验证,并通过改变用户ID和组ID来切换用户身份。源码中还包括一些其他的安全检查和选项处理逻辑。通过理解su命令的源码,我们可以更好地理解和使用Linux操作系统中的用户管理功能。

    2年前 0条评论
  • fiy的头像
    fiy
    Worktile&PingCode市场小伙伴
    评论

    Linux中的su命令用于切换用户身份。通过su命令,普通用户可以切换为其他用户(通常是超级用户)来执行特权操作。如果没有指定要切换的用户名称,则默认切换到超级用户root。

    下面将介绍Linux中su命令的源码实现。

    ## 1. su命令的工作原理

    su命令的基本工作原理如下:

    1. 用户在终端输入su命令,并指定要切换的目标用户。
    2. su命令会验证当前用户是否有权限切换到目标用户。
    3. 如果当前用户有权限,su命令会要求用户输入目标用户的密码。
    4. 如果目标用户密码验证通过,su命令会通过setuid()系统调用改变进程的有效用户ID(effective UID),以切换到目标用户身份。
    5. 切换完成后,su命令会启动一个新的shell进程,并加载目标用户的环境变量,用户可以在新的shell中执行特权操作。

    ## 2. su命令源码分析

    在Linux系统中,su命令的源码一般位于`/bin/su`或`/usr/bin/su`目录下。以下是su命令的源码实现的基本结构:

    “`c
    #include
    #include
    #include
    #include

    int main(int argc, char *argv[]) {
    // 解析命令行参数,获取要切换的目标用户
    // …

    // 验证当前用户是否有权限切换到目标用户
    // …

    // 要求用户输入目标用户的密码
    // …

    // 验证目标用户密码
    // …

    // 修改进程的有效用户ID,切换到目标用户身份
    // …

    // 启动新的shell进程,加载目标用户的环境变量
    // …

    return 0;
    }
    “`

    下面对源码中的关键部分进行详细解析。

    ### 解析命令行参数

    su命令可以接受命令行参数来指定要切换的目标用户。在源码中,可以使用`getopt()`函数来解析命令行参数,获取要切换的目标用户:

    “`c
    #include

    int getopt(int argc, char * const argv[], const char *optstring);

    int main(int argc, char *argv[]) {
    int opt;
    char *target_user = NULL;

    while ((opt = getopt(argc, argv, “l:”)) != -1) {
    switch (opt) {
    case ‘l’:
    target_user = optarg;
    break;
    default:
    // 处理参数错误
    break;
    }
    }

    // 根据target_user切换用户身份
    // …

    return 0;
    }
    “`

    在上述代码中,使用了`getopt()`函数来解析命令行参数。`optstring`参数指定了可识别的短选项,比如`”l:”`表示接受以`-l`开头的参数,并且参数值存储在`optarg`变量中。

    ### 验证当前用户权限

    su命令需要验证当前用户是否有权限切换到目标用户。通常情况下,只有超级用户(root)才有权限切换为其他用户。

    在源码中,可以使用`getuid()`函数获取当前用户的实际用户ID(real UID),通过比较实际用户ID和超级用户ID(0)来判断当前用户是否有权限:

    “`c
    #include

    int getuid(void);

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

    uid_t real_uid = getuid();

    if (real_uid != 0) {
    // 当前用户非超级用户,无权限切换
    // …
    }

    // …

    return 0;
    }
    “`

    在上述代码中,使用了`getuid()`函数获取当前用户的实际用户ID,在Linux中,超级用户ID通常为0。如果实际用户ID不是0,则表示当前用户非超级用户,无权限切换。

    ### 要求用户输入密码

    如果当前用户有权限切换到目标用户,su命令会要求用户输入目标用户的密码。密码的输入可以通过`getpass()`函数实现:

    “`c
    #include

    char *getpass(const char *prompt);

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

    char *password = getpass(“Password: “);

    // …

    return 0;
    }
    “`

    在上述代码中,使用了`getpass()`函数来提示用户输入密码,并将输入的密码存储在`password`变量中。

    ### 验证目标用户密码

    su命令需要验证用户输入的目标用户密码是否正确。这可以通过与目标用户的密码进行比较来实现。Linux系统中的密码文件通常是`/etc/passwd`,其中存储了用户的信息,包括密码的哈希值。

    在源码中,可以使用`getpwnam()`函数来获取目标用户的相关信息,包括密码的哈希值。然后可以使用`crypt()`函数将用户输入的密码进行哈希计算,与获取到的哈希值进行比较来验证密码是否正确:

    “`c
    #include
    #include #include

    struct passwd *getpwnam(const char *name);
    char *crypt(const char *key, const char *salt);

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

    struct passwd *user_info = getpwnam(target_user);
    char *hash = user_info->pw_passwd;
    char *input_password = getpass(“Password: “);
    char *input_hash = crypt(input_password, hash);

    if (strcmp(input_hash, hash) != 0) {
    // 密码验证不通过
    // …
    }

    // …

    return 0;
    }
    “`

    在上述代码中,使用了`getpwnam()`函数来获取目标用户的相关信息。其中,`pw_passwd`字段存储了密码的哈希值。然后使用`crypt()`函数将用户输入的密码与获取到的哈希值进行比较,如果不一致,则表示密码验证失败。

    ### 修改进程的有效用户ID

    如果密码验证通过,su命令会使用`setuid()`函数修改进程的有效用户ID,以切换到目标用户身份:

    “`c
    #include

    int setuid(uid_t uid);

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

    uid_t target_uid = user_info->pw_uid;

    if (setuid(target_uid) != 0) {
    // 切换用户身份失败
    // …
    }

    // …

    return 0;
    }
    “`

    在上述代码中,使用了`setuid()`函数将进程的有效用户ID修改为目标用户的用户ID。如果返回值不等于0,则表示切换用户身份失败。

    ### 启动新的shell进程

    最后,su命令会通过`execve()`函数启动一个新的shell进程,并加载目标用户的环境变量:

    “`c
    #include

    int execve(const char *filename, char *const argv[], char *const envp[]);

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

    char *shell = “/bin/bash”;
    char *const new_argv[] = {shell, NULL};

    if (execve(shell, new_argv, environ) != 0) {
    // 启动新shell进程失败
    // …
    }

    // …

    return 0;
    }
    “`

    在上述代码中,使用了`execve()`函数将当前进程替换为一个新的shell进程。`filename`参数指定了要执行的程序路径,`argv`参数指定了传递给新进程的命令行参数,`envp`参数指定了新进程的环境变量(使用`environ`全局变量)。

    这样,su命令的源码实现基本完成。用户在启动su命令后,通过以上流程,可以切换到其他用户身份,并在新的shell中执行特权操作。

    2年前 0条评论
注册PingCode 在线客服
站长微信
站长微信
电话联系

400-800-1024

工作日9:30-21:00在线

分享本页
返回顶部