• Linux 用户信息、切换用户


    UID、EUID、GID、EGID

    几个常见用户信息概念:UID、EUID、GID、EGID

    UID:当前进程的真实用户ID;
    EUID:有效用户ID;
    真实组ID:GID;
    有效组ID:EGID;

    可以通过下面这组函数获取和设置当前进程的用户信息:

    #include <sys/types.h>
    #include <unistd.h>
    
    uid_t getuid();          /* 获取真实用户ID */
    uid_t geteuid();         /* 获取有效用户ID */
    
    gid_t getgid();                      /* 获取真实组ID */
    gid_t getegid();         /* 获取有效组ID */
    
    int setuid(uid_t uid);   /* 设置真实用户ID */
    int seteuid(uid_t uid);  /* 设置有效用户ID */
    
    int setgid(gid_t gid);   /* 设置真实组ID */  
    int setegid(gid_t gid);  /* 获取有效组ID */
    

    一个进程有两个用户ID:UID和EUID。有什么区别呢?
    EUID存在的目的是方便资源访问,使得运行程序的用户拥有该程序的有效用户的权限,比如su程序,任何用户都可以用它来修改自己的账户信息,但修改账户时,su程序不得不访问/etc/passwd文件,而访问该文件是需要root权限的。

    以普通用户身份启动的su程序,如何能访问/etc/passwd文件呢?
    诀窍在于EUID。ls命令可以查看到,su程序所有者root,且被设置了set-user-id标志。这个标志表示,任何普通用户运行su程序时,其有效用户就是该程序的所有者root。根据有效用户的含义,任何运行su程序的普通用户都能访问/etc/passwd文件。有效用户为root的进程,称为特权进程(privileged processes)。
    EGID含义与EUID类似,给运行目标程序的组用户提供有效组的权限。

    比如,ls命令查看uid_test程序权限位,其中"s"表示set-user-id标志。

    $ ls -al uid_test
    -rwsrwsr-x 1 root root 10391 May  1 14:39 uid_test
    

    下面程序测试进程的UID和EUID的区别

    #include <unistd.h>
    #include <stdio.h>
    
    int main()
    {
        uid_t uid = getuid(); // Get the real user ID
        uid_t euid = geteuid(); // Get the effective user ID
        printf("real userid is %d, effective userid is %d\n", uid, euid);
        return 0;
    }
    

    编译完成后,需要将生成的可执行文件(uid_test)所有者设置为root,并设置该文件的set-user-id标志,然后运行该程序查看UID和EUID。具体操作:

    $ sudo chown root:root uid_test # 修改目标文件的所有者为root
    $ ls -l uid_test
    -rwxrwxr-x 1 root root 10391 May  1 14:39 uid_test
    
    $ sudo chmod +s uid_test # 设置目标文件的set-user-id标志
    $ ls -al uid_test
    -rwsrwsr-x 1 root root 10391 May  1 14:39 uid_test
    
    $ ./uid_test # 运行程序
    real userid is 1000, effective userid is 0
    

    可以看到,UID是启动程序的用户的ID,EUID是root账户(文件所有者)的ID。

    切换用户

    例程:从root用户切换到普通用户。
    要求程序以root身份启动,而我的登录用户名为martin的用户uid和gid分别为1000,1000。为简化程序设计,直接将其作为要切换的普通目标用户。

    #include <stdio.h>
    #include <unistd.h>
    
    /**
    * 从root用户切换到目标用户(user_id, gp_id)
    * root 用户uid = 0, gid = 0
    */
    static bool switch_to_user(uid_t user_id, gid_t gp_id)
    {
        /* 先确保目标用户不是root */
        if ((user_id == 0) && (gp_id == 0)) {
            return false;
        }
        /* 确保当前用户是合法用户: root或者目标用户 */
        gid_t gid = getgid();
        uid_t uid = getuid();
        if (((gid != 0) || (uid != 0)) && ((gid != gp_id) || (uid != user_id))) {
            return false;
        }
        /* 如果不是root, 则已经是目标用户 */
        if (uid != 0) {
            return true;
        }
    
        /* 切换到目标用户 */
        if ((setgid(gp_id) < 0) || (setuid(user_id) < 0)) {
            return false;
        }
        return true;
    }
    
    /**
    * 要求以root身份启动程序
    * user_id = 1000, gp_id = 1000 是我的登录用户 martin
    */
    int main()
    {
        printf("current uid = %d, euid = %d\n", getuid(), geteuid());
        switch_to_user(1000, 1000);
        printf("current uid = %d, euid = %d\n", getuid(), geteuid());
        return 0;
    }
    

    参考

    《Linux高性能服务器编程》

  • 相关阅读:
    【CSS学习】--- 背景
    线程运行诊断
    Mysql变量、存储过程、函数、流程控制
    设计模式之外观模式(门面模式)
    Spring的JdbcTemplate使用教程
    @AspectJ注解的value属性
    自定义Yaml解析器替换Properties文件
    @Import导入自定义选择器
    Spring中Bean命名源码分析
    Java操作fastDFS
  • 原文地址:https://www.cnblogs.com/fortunely/p/16213667.html
Copyright © 2020-2023  润新知