基于qemu-riscv从0开始构建嵌入式linux系统ch15. linux多用户管理

inittab修改

ch13中我们使用了-/bin/sh作为init进程的RESPAWN|ASKFIRST阶段执行,如此一来,系统在启动时无需输入用户名密码将直接使用root权限启动。而本节将配置多用户管理,因此inittab修改为:

::sysinit:/etc/init.d/rcS
console::respawn:/sbin/getty 38400 console
console::restart:/sbin/init
console::ctrlaltdel:/sbin/reboot

getty

为什么要使用getty替换原来的sh才能使用多用户管理呢,那么/sbin/getty就是我们探究的重点了,源码位于busybox-1.33.1/loginutils/getty.c:550:getty_main。getty_main主要进行了一些初始化操作,绑定tty设备到stdin\stdout\stderr等操作,然后调用了static char *get_logname(void)函数,从终端输入获取登录用户输入,然后调用执行login命令,相关代码片段如下:

……
716  logname = get_logname();
……
735  BB_EXECLP(G.login, G.login, "--", logname, (char *)0);
……

login

login源码位于busybox-1.33.1/loginutils/login.c:313:login_main,注意到以下调用关系链。

ask_and_check_password
    --> ask_and_check_password_extended
        --> check_password
            --> get_passwd
                --> getspnam_r
                    --> getXXnam_r
                        --> get_S
                        --> parse_file

在get_S会使用配置文件”/etc/passwd”、”/etc/group”、”/etc/shadow”建立db数据库,以下摘抄代码片段:

#ifndef _PATH_PASSWD
#define _PATH_PASSWD  "/etc/passwd"
#endif
#ifndef _PATH_GROUP
#define _PATH_GROUP   "/etc/group"
#endif
#ifndef _PATH_SHADOW
#define _PATH_SHADOW  "/etc/shadow"
#endif

static const struct const_passdb const_pw_db = {
	_PATH_PASSWD, PW_DEF,
	{
		offsetof(struct passwd, pw_name),       /* 0 S */
		offsetof(struct passwd, pw_passwd),     /* 1 s */
		offsetof(struct passwd, pw_uid),        /* 2 I */
		offsetof(struct passwd, pw_gid),        /* 3 I */
		offsetof(struct passwd, pw_gecos),      /* 4 s */
		offsetof(struct passwd, pw_dir),        /* 5 s */
		offsetof(struct passwd, pw_shell)       /* 6 s */
	},
	sizeof(PW_DEF)-1, sizeof(struct passwd)
};
static const struct const_passdb const_gr_db = {
	_PATH_GROUP, GR_DEF,
	{
		offsetof(struct group, gr_name),        /* 0 S */
		offsetof(struct group, gr_passwd),      /* 1 s */
		offsetof(struct group, gr_gid),         /* 2 I */
		offsetof(struct group, gr_mem)          /* 3 m (char **) */
	},
	sizeof(GR_DEF)-1, sizeof(struct group)
};
#if ENABLE_USE_BB_SHADOW
static const struct const_passdb const_sp_db = {
	_PATH_SHADOW, SP_DEF,
	{
		offsetof(struct spwd, sp_namp),         /* 0 S Login name */
		offsetof(struct spwd, sp_pwdp),         /* 1 s Encrypted password */
		offsetof(struct spwd, sp_lstchg),       /* 2 l */
		offsetof(struct spwd, sp_min),          /* 3 l */
		offsetof(struct spwd, sp_max),          /* 4 l */
		offsetof(struct spwd, sp_warn),         /* 5 l */
		offsetof(struct spwd, sp_inact),        /* 6 l */
		offsetof(struct spwd, sp_expire),       /* 7 l */
		offsetof(struct spwd, sp_flag)          /* 8 r Reserved */
	},
	sizeof(SP_DEF)-1, sizeof(struct spwd)
};
#endif

static struct statics *get_S(void)
{
	if (!ptr_to_statics) {
		ptr_to_statics = xzalloc(sizeof(S));
		memcpy(&S.db[0], &const_pw_db, sizeof(const_pw_db));
		memcpy(&S.db[1], &const_gr_db, sizeof(const_gr_db));
#if ENABLE_USE_BB_SHADOW
		memcpy(&S.db[2], &const_sp_db, sizeof(const_sp_db));
#endif
#if ENABLE_FEATURE_CLEAN_UP
		atexit(free_static);
#endif
	}
	return ptr_to_statics;
}

代码阅读到这里就能发现其实是一套libpwdgrp的机制来支持用户、用户组权限的管理、密码管理等机制,阅读busybox-1.33.1/docs/BusyBox.txt:4323这里可以看到busybox使用配置CONFIG_USE_BB_PWD_GRP选项后会使用上述机制读取这三个配置文件,否则会使用libc中的NSS库。这三个文件的内容格式还是比较容易理解的,就是每一行描述一条用户参数,使用:分割不同的属性,而:的顺序正如上面代码struct const_passdb结构的off里的描述的那样。这里建议大家可以通过搜索引擎查找对这三个配置文件格式解释,并结合我这里贴出的源码一起阅读就理解的很清晰了。

编写配置文件

这里我们创建一些常规的用户和用户组,注意是系统管理员为root用户和而xiaoming用户是我们模拟普通用户。shadow的第二项Encrypted password是具有一定格式的采用不同的加密算法的,像是md5加密是可能被破解得到明文的,因此/etc/shadow一般需要配置为只有管理员root可以读取,而且加密算法最好使用sha-512。

/etc/passwd

root:x:0:0:root:/home/root:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
xiaoming:x:1000:1000:Linux User,,,:/home/xiaoming:/bin/sh

/etc/group

root:x:0:
daemon:x:1:
bin:x:2:
sys:x:3:
sudo:x:27:xiaoming
users:x:100:
nogroup:x:65534:
xiaoming:x:1000:

/etc/shadow

root:8f3SuzAlYA9zc:18802:0:99999:7:::
daemon:*:16092:0:99999:7:::
bin:*:16092:0:99999:7:::
sys:*:16092:0:99999:7:::
nobody:*:16092:0:99999:7:::
xiaoming:8KRJzPtwP/eRQ:18802:0:99999:7:::

/etc/busybox.conf

配置完成,最后这里关于权限管理部分我们再配置一个/etc/busybox.conf,内容如下:

[SUID]
su = ssx 0.0 # run with euid=0/egid=0
id = ssx 0.0 # run with euid=0/egid=0
halt = ssx 0.0 # run with euid=0/egid=0
reboot = ssx 0.0 # run with euid=0/egid=0
shutdown = ssx 0.0 # run with euid=0/egid=0
passwd = --- 0.0 # disabled for all user except for root

/etc/busybox.conf的解析在busybox启动,busybox-1.33.1/libbb/appletlib.c中:main–>parse_config_file进行解析。

ch15-0

本节为我们的系统添加多用户管理,现在我们登录时可以输入用户名密码进行登录了。教程到这个阶段系统性的配置接近尾声,后续我们会对linux里杂七杂八的子系统做一下实验研究,相关性会比较零散。

本教程的
github仓库:https://github.com/QQxiaoming/quard_star_tutorial
gitee仓库:https://gitee.com/QQxiaoming/quard_star_tutorial
本节所在tag:ch15