用户和组

  • 每个用户都有一个唯一的用户ID,且每个用户可以属于多个组;每个组都有唯一一个名称和一个组ID
  • 用户和组ID是为了确定各种系统资源的使用权以及对进程访问资源的权限加以控制
  • 针对系统的每一个用户账号,系统密码文件/etc/passwd会有一行记录与其对应,每行都包含7个字段,其间用冒号分隔,比如sone:x:1000:1000:pty,,,:/home/sone:/bin/bash,各个字段定义如下
  1. 用户名字段
  2. 经过加密的密码,通常如果启用了shadow密码,那么该字段为x,真正加密的密码保存于shadow文件中
  3. 用户ID
  4. 首选属组的组ID
  5. 注释
  6. 该用户的主目录
  7. 登录shell
  • 相对的,每一个group在/etc/group文件中也有记录,每条记录包含4个字段,以冒号分隔,比如sone:x:1000:,四个字段的定义如下
  1. 组名
  2. 经过加密的密码,同用户记录一样,通常为x
  3. 组ID
  4. 用户列表,表示属于该组的用户名列表,其中以逗号分隔

相关函数

  • 与/etc/passwd相关的函数集原型以及结构体如下
       #include <sys/types.h>
       #include <pwd.h>

         struct passwd {
               char   *pw_name;       /* username */
               char   *pw_passwd;     /* user password */
               uid_t   pw_uid;        /* user ID */
               gid_t   pw_gid;        /* group ID */
               char   *pw_gecos;      /* user information */
               char   *pw_dir;        /* home directory */
               char   *pw_shell;      /* shell program */
           };
       //根据用户名获得相关的记录,如果在文件中找不到记录返回NULL
       struct passwd *getpwnam(const char *name);
       //根据用户ID获得相关记录,找不到的话返回NULL
       struct passwd *getpwuid(uid_t uid);
       /*以下三个函数是用来扫描passwd文件中所有记录的*/
       struct passwd *getpwent(void);
       void setpwent(void);
       void endpwent(void);
  • 如果想要扫描/etc/passwd文件中的记录,那么首先调用getpwent函数获得指向第一条记录的指针,然后该函数自动将指针指向下一条记录;当扫描完以后调用endpwent将其关闭;另外可以调用endpwent函数将指针重新指向文件的第一条记录
  • 与/etc/group相关的函数集原型以及结构体如下,功能和passwd文件的相关函数类似
       #include <sys/types.h>
       #include <grp.h>
       struct group {
               char   *gr_name;        /* group name */
               char   *gr_passwd;      /* group password */
               gid_t   gr_gid;         /* group ID */
               char  **gr_mem;         /* NULL-terminated array of pointers
                                          to names of group members */
        };

       struct group *getgrnam(const char *name);

       struct group *getgrgid(gid_t gid);

       struct group *getgrent(void);
       void setgrent(void);
       void endgrent(void);
  • 与/etc/shadow相关
       #include <shadow.h>
       struct spwd {
               char *sp_namp;     /* Login name */
               char *sp_pwdp;     /* Encrypted password */
               long  sp_lstchg;   /* Date of last change
                                     (measured in days since
                                     1970-01-01 00:00:00 +0000 (UTC)) */
               long  sp_min;      /* Min # of days between changes */
               long  sp_max;      /* Max # of days between changes */
               long  sp_warn;     /* # of days before password expires
                                     to warn user to change it */
               long  sp_inact;    /* # of days after password expires
                                     until account is disabled */
               long  sp_expire;   /* Date when account expires
                                     (measured in days since
                                     1970-01-01 00:00:00 +0000 (UTC)) */
               unsigned long sp_flag;  /* Reserved */
           };
       //根据用户名查找相应的密码记录
       struct spwd *getspnam(const char *name);
       //遍历处理函数
       struct spwd *getspent(void);
       void setspent(void);
       void endspent(void);
  • 验证密码所使用的加密函数原型如下
#include <unistd.h>

char* crypt(const char* key,const char* salt);
  • crypt算法会接受一个最长可达8字符的密码,并对其进行加密,若加密成功返回指向该密文的指针;salt参数是一个指向两个字符长度的字符串,用来改变加密算法;一般,会将/etc/shadow对应的密码密文传进去,该函数只会截取前两个字符,只有这样才能够对候选密码进行验证。在编译该函数时需要开启-lcrypt选项,指定链接库
  • 在需要用户输入密码时,常常调用getpass函数,可以屏蔽回显;该函数会打印提示信息prompt,并返回输入的密码,原型如下
       #include <unistd.h>

       char *getpass(const char *prompt);

进程凭证

  • 每个进程都有一套用户和组ID,分别是实际用户和组ID,有效用户和组ID,设置用户和组ID,文件系统用户和组ID(linux专有)以及辅助组ID
  • 一般在登录系统时,登录shell会从/etc/passwd文件中读取有关当前登录用户的用户ID和组ID,然后将shell进程的实际用户ID和实际组ID设置为查询到的用户ID和组ID;并且后续的子进程会继承父进程的实际用户和组ID
  • 进程的有效用户和组ID决定当前进程是否有权限访问系统资源,如文件或者IPC对象;有效用户ID为0的进程被称为特权进程,某些系统调用只能由特权进程执行;改变一个进程的有效ID的方法有两种,其一是调用相关的系统调用,其二是通过设置用户和组ID
  • 设置用户和组ID(set-user-ID和set-group-ID)可以将进程的有效用户和组ID置为可执行文件的实际用户和组ID;例如,对于一个可执行文件来说,如果设置了设置用户ID权限位并且该文件的实际用户ID为root,那么普通用户在执行该文件时会具有root用户的所有权限,因为当前进程的有效用户ID会被设置为root;比如说linux系统的/bin目录下有一个passwd可执行程序,用来更改密码,它的权限位为"-rwsr-xr-x",而正常情况下同组用户和其他用户对于shadow文件的修改没有写权限,但是因为它设置了设置用户ID位,则当执行passwd的时候,执行进程的有效用户ID被设置为root,进而可以对shadow文件进行修改
  • 与设置用户和组ID相关的还有一组ID叫做保存set-user-ID和保存set-group-ID,保存设置用户和组ID由有效用户和组ID复制而来,为了方便进程切换有效用户和组ID
  • 文件系统用户和组ID一般都和有效用户和组ID等价,除非调用特定的系统调用去改变,一般不作考虑
  • 辅助组ID记录进程所属的若干附加的组,新进程从父进程继承这些ID
  • 获取用户和组相关ID的函数原型如下,getuid和getgid分别是获取当前进程的实际用户ID和实际组ID;geteuid和getegid分别获取当前进程的有效用户ID和有效组ID
       #include <unistd.h>
       #include <sys/types.h>

       uid_t getuid(void);
       uid_t geteuid(void);
       gid_t getgid(void);
       gid_t getegid(void);
  • 修改有效用户和组ID的函数如下,对于非特权进程来讲,setuid只能将进程的有效ID设置为实际用户ID或者保存set-user-ID,如果设置为其他值,调用出错返回-1;对于特权进程来讲,setuid可以将有效ID,实际ID和保存设置ID设置为任意值,但是会丢失所有特权,且不可逆
       #include <sys/types.h>
       #include <unistd.h>

       int setuid(uid_t uid);
       int setgid(gid_t gid);
  • 如果想要防止不可逆的情况,可以使用下面一组函数,对于非特权进程来说调用的规则和上述函数类似,而对于特权进程来说,seteuid只修改有效用户ID为任意值,这意味着在将有效用户ID改为其他值以后可以重新将有效用户ID设置为0
       #include <sys/types.h>
       #include <unistd.h>

       int seteuid(uid_t euid);
       int setegid(gid_t egid);
  • 在linux中,有一组专用的对于查看和修改各种ID信息的函数,调用规则与上述类似,只是更加方便,原型如下
       #define _GNU_SOURCE         /* See feature_test_macros(7) */
       #include <unistd.h>

       int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
       int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
       int setresuid(uid_t ruid, uid_t euid, uid_t suid);
       int setresgid(gid_t rgid, gid_t egid, gid_t sgid);
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,519评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,842评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,544评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,742评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,646评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,027评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,169评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,324评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,268评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,299评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,996评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,591评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,911评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,288评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,871评论 2 341

推荐阅读更多精彩内容

  • 一、USERS UID为0的用户为管理员用户,任何一个UID为0的用户,都可为管理员用户若系统没有了UID=0的管...
    JevonWei阅读 2,191评论 0 2
  • 众所周知,Linux是一个多用户、多任务(Multi-Tasks、Multi-Users)的操作系统。那么Linu...
    学渣角鹿白阅读 5,807评论 0 9
  • 要对计算机系统进行相关的操作,就需要有账号,如果很多账号需要对同一文件具有相同的操作权限,那么这个时候就涉及到组...
    ghbsunny阅读 501评论 0 0
  • 用户和组 一、用户: 是用来操作系统中不同功能的身份. Linux系统中用户的分类 1)超级用户: roo...
    崔千易阅读 670评论 0 0
  • 今日课表:2K热身+18K 细雨清晨的锦城湖,湿湿的花香袭人,适合跑步的好天气。 头天立了Flag,尝试18K配速...
    小冠没道理阅读 171评论 0 0