Unix用户终端登录过程分析
login 之前
UNIX系统中,用户在终端登录过程大致为(Linux系统与之差异不大,主要是是配置文件组织形式有差异):
- 系统自举(系统启动初始化)时,内核创建进程 1 号进程init,init 进入多用户模式,读取 /etc/tty
- 对每一个允许登录的终端设备,init 依次调用 fork,子进程 exec getty
- getty 对终端设备调用 open 函数,以读写方式打开,也可能在某一等待连接线路的设备处等待
- 文件描述符 0 1 2 被设置指向该设备
- 输出 login: 字符串等待用户输入
- 输入成功后,按照以下方式调用login程序
1
execle("/bin/login", "login", "-p", username, (char *)0, envp);
getty 以终端名称和在 gettytab 中说明的环境变量字符串,为 login 创建一个环境参数 envp。-p 表示保留该环境参数。
上图中的所有进程目前都具有 root 权限,因为直接从 init 继承 fork,而继承了权限。并且 exec 并不改变进程 ID,下面三个进程的 ID 相同。
这部分说的终端都不是伪终端
login
接下来的 login 的工作是:
- getpwnam 取得用户口令文件
- getpass 读取用户输入密码
- crypt 对输入密码加密,并于 shadow 文件中的 pw_passwd 字段比较
- 若口令无效,exit(1)
- init 进程读取返回值后,再次 fork 执行 getty,重复上述过程。
以上是UNIX系统的用户登录验证过程,Linux 等后续较新的系统使用更灵活的 PAM 验证方案。
login 之后
完成 login 之后:
chdir 到用户起始目录
chown 改变当前终端所有权为当前登录用户
改变当前终端设备的访问权限为 “用户读写”
setgid, initgroups 设置进程组 ID
用 login 得到的信息,初始化:HOME目录、shell、username、PATH 等
setuid 设置进程用户 ID 为当前登录用户的 ID,并启动该用户设置的登录 shell
1
execl("/bin/sh", "-sh", (char *)0);
此处是由root 调用的 setuid,所以可以设置进程的:实际用户ID、有效用户ID和保存用户ID。
- shell 读取启动文件,.profile 之类(可能由其他名字)
- 在终端输出输入提示符,等待用户输入命令。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!