agetty深入分析
前言:
了解agetty对于我们使用和安全设置你的系统意义重大,通过本文可以了解登录管理机制、以及交互环境的行为干预等。
但是这个主题实际内容还是比较多的,知识点很多,又怕有遗漏,又怕写的又臭又长。网上其他人也有介绍,但是很多是蜻蜓点水,一带而过,我尽量是写就写好吧,尽量实验为主,但是确实很费心。有不足还请谅解。
实验环境
我是在linux ,centos,3.10版本内核上做的测试,所以主要针对小红帽的centos做讲解
[root@aozhejin2 /usr/local/src]$cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)
[root@aozhejin2 /usr/local/src]$uname -r
3.10.0-1160.62.1.el7.x86_64
[root@aozhejin2 ~]$systemd-analyze
Startup finished in 764ms (kernel) + 1.598s (initrd) + 30.920s (userspace) = 33.283s
一、what is agetty?
agtty 是 管理员程序/命令,它是linux版本getty(),用来设置终端类型、模式、速度和termios(里面包含各种选项比如自动登录等)、ldisc等。
它被init程序调用 它是 bios-kernelboot-init-getty-login-shell系列中的第三个进程(前面mbr、grub等先忽略)。 最终将用户与 Linux 系统连接起来。agetty读取用户的loginname并以loginname作为参数调用登录命令。在读取名称时,agetty会尝试使系统适应正在使用的设备的速度和类型。您必须指定一个端口,agetty将在/dev目录 中搜索该端口。您可以使用 -,在这种情况下agetty从标准输入读取。您还必须指定baudrate,它可以是逗号分隔的速率列表,agetty 将逐步执行。或者,您可以指定term,它用于覆盖 TERM 环境变量。
[root@aozhejin2 /usr/lib/systemd/system]$agetty - CentOS Linux 7 (Core) Kernel 3.10.0-1160.62.1.el7.x86_64 on an x86_64 aozhejin2 login: root ....
Linux 系统运行后可以通过三种方式登录:
1.在本地通过字符模式连接。这可能是系统控制台、伪终端(系统控制台访问)或连接(可能通过调制解调器)到串行线路的真实终端。
调制解调器部分可参看 https://en.wikipedia.org/wiki/RS-232 也就是串口(ttyS0等),在嵌入式设备等还是有广泛的应用
要使用串行控制台,只需在内核命令行上使用 console=ttyS0,systemd 会自动为您启动agetty
2.通过图形界面在本地或远程。
3.通过某些协议(如 rsh、ssh 或 telnet)进行远程访问(我这里是通过跳板机登录到实验环境)。
对于本地非图形界面:
1.对于任何本地非图形界面,运行程序 /sbin/agetty(或有时 /sbin/mingetty等,看你的系统)。
1) 按照sysv方式:
getty 的启动是从/etc/inittab中针对 SysV 版本的 init 完成的,并由 Upstart 中的启动配置文件(每个终端一个)完成。
2)按照systemd方式:
本机采用这种方式,在 systemd 中,每个 tty 设备都会指向 getty@.service 服务的符号链接表示 。
2. getty(或agetty等) 在 stdout 设备(一般是屏幕)上发出登录提示(或等待调制解调器上的连接,然后发出登录提示)。
3.输入用户名后,getty(agetty等) 执行 /bin/login程序。login程序 读取并验证密码,然后对 /etc/passwd 中为登录用户指定的 shell 程序执行 exec。
4.当用户注销时,getty(agetty) 检测进程终止并重置终端以建立新连接。
注意登录管理模式:
1.SysV(也称 System v) init模式最典型的是采用6个run-levels机制。
2.Upstart 是用来替代SysV init 模式而开发的,但是现代流行的系统中已不多见这种方式。
3.systemd采用是服务管理机制,它替换SysV init和Upstart 来初始化启动过程。RHEL6采用的是Upstart 方式,RHEL6之前用的是SysVinit
systemd是红帽7和Ubuntu(15.04)之后采用的方式(centos6上你可以看下,处理方式还是不一样的)。
这个几种模式不了解,你也无从谈起安全防范和攻击等事件。
本机采用的systemd,而systemd有两种在文本控制台上显示登录提示
1. getty@.service(即非串行TTY)负责虚拟终端(VT) 登录提示,即显示在/dev/tty1和类似设备中的 VGA 屏幕上的提示。
[root@aozhejin2 ~]$locate getty@.service /usr/lib/systemd/system/getty@.service
如果我们想建多个,则cp 这个文件成 getty@tty2.service、getty@tty3.service等
2.serial-getty@.service负责所有其他终端,包括/dev/ttyS0等串行端口
[root@aozhejin2 ~]$locate serial-getty@.service /usr/lib/systemd/system/serial-getty@.service
另外一种是 console
3.console-getty.service,/dev/console 和 container-getty@.service 实例
[root@aozhejin2 ~]$locate console-getty.service /usr/lib/systemd/system/console-getty.service [root@aozhejin2 ~]$cat /usr/lib/systemd/system/console-getty.service [Unit] Description=Console Getty Documentation=man:agetty(8) After=systemd-user-sessions.service plymouth-quit-wait.service ConditionPathExists=/dev/console After=rc-local.service getty-pre.target Before=getty.target [Service] ExecStart=-/sbin/agetty --noclear --keep-baud console 115200,38400,9600 $TERM Type=idle Restart=always RestartSec=0 UtmpIdentifier=cons TTYPath=/dev/console TTYReset=yes TTYVHangup=yes KillMode=process IgnoreSIGPIPE=no SendSIGHUP=yes [Install] WantedBy=getty.target
在内核控制台*getty@.service上实例化都由各自的一些生成器来生成(他们用于启用 getty 实例的生成器)
[root@aozhejin2 ~]$ls /usr/lib/systemd/system-generators kdump-dep-generator.sh rpc-pipefs-generator systemd-efi-boot-generator systemd-hibernate-resume-generator systemd-sysv-generator lvm2-activation-generator systemd-cryptsetup-generator systemd-fstab-generator systemd-rc-local-generator nfs-server-generator systemd-debug-generator systemd-getty-generator systemd-system-update-generator
二、调用agetty
首先看下systemd运行情况,注意这里是通过systemd在管理相关服务包括agetty的启动等
[root@aozhejin2 ~]$systemctl list-units | egrep -i "tty|login" sys-devices-platform-serial8250-tty-ttyS0.device loaded active plugged /sys/devices/platform/serial8250/tty/ttyS0 sys-devices-platform-serial8250-tty-ttyS1.device loaded active plugged /sys/devices/platform/serial8250/tty/ttyS1 sys-devices-platform-serial8250-tty-ttyS2.device loaded active plugged /sys/devices/platform/serial8250/tty/ttyS2 sys-devices-platform-serial8250-tty-ttyS3.device loaded active plugged /sys/devices/platform/serial8250/tty/ttyS3 getty@tty1.service loaded active running Getty on tty1 getty@tty6.service loaded active running Getty on tty6 systemd-logind.service loaded active running Login Service system-getty.slice loaded active active system-getty.slice getty.target loaded active active Login Prompts
查看进程运行情况
[root@aozhejin2 /usr/lib/systemd/system]$ps -ef | grep agetty root 870 1 0 2022 tty1 00:00:00 /sbin/agetty --noclear tty1 linux root 11148 1 0 Mar29 tty6 00:00:00 /sbin/agetty --noclear tty6 linux
man getty手册以下内容开头:
getty打开一个 tty设备,提示输入登录名并调用 /bin/login 命令。它通常由 init(8)调用。 请注意 getty、 agetty、 fgetty和 mingetty只是getty的不同实现。 init运行最显着的效果是它产生一个登录到每个LINUX虚拟控制台。显示此登录的是上面inittab行中指定的getty(system v方式)
(或有时是 mingetty)命令。输入登录名后,agetty将调用/bin/login程序,然后提示用户输入密码。 登录程序执行一个 shell。当 shell 死亡时(由于用户退出会话)getty只是重建。
https://man7.org/linux/man-pages/man8/agetty.8.html
agetty 打开一个 tty设备,提示输入登录名并调用/bin/login 命令。它通常由init (8) 调用。
agetty有几个非标准功能,可用于硬连线和拨入线:
• 使 tty 设置适应奇偶校验位并擦除、终止、读取登录时的行尾字符和大写字符姓名。该程序可以处理 7 位字符,包括偶数、奇数、
无或空格奇偶校验,以及无奇偶校验的 8 位字符。
识别以下特殊字符:Control-U (杀); DEL 和退格键(擦除);回车和换行进给(行尾)。另请参阅--erase-chars和
--kill-chars选项。
• 可选地从 CONNECT 消息中推断出波特率由与 Hayes(tm) 兼容的调制解调器生产。
• 可选择不挂机打开的线路(对回调应用程序有用)。
• 可选择不显示/etc/issue的内容文件。
• 可选择显示替代问题文件或目录而不是/etc/issue或/etc/issue.d。
• 可选择不要求登录名。
• 可选择调用非标准登录程序而不是 /bin/login。
• 可选择打开硬件流控制。
• 可选择强制线路为本地线路,无需载波检测。
该程序不使用/etc/gettydefs (System V) 或/etc/gettytab (SunOS 4) 文件。
/sbin/agetty是一个二进制程序
[root@aozhejin2 /usr/lib/systemd/system]$file /sbin/agetty /sbin/agetty: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=3b10f282c75c8419ff4abb5738389e7c4cb69bc0, stripped
/bin/login
[root@aozhejin2 /usr/lib/systemd/system]$stat /bin/login File: â/bin/loginâ Size: 37248 Blocks: 80 IO Block: 4096 regular file Device: fd00h/64768d Inode: 134327918 Links: 1 Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2023-03-29 08:17:15.942772765 +0800 Modify: 2021-02-03 00:31:53.000000000 +0800 Change: 2021-09-23 10:26:40.773848683 +0800 Birth: -
采用的是sysv版本的
[root@aozhejin2 /usr/lib/systemd/system]$file /bin/login
/bin/login: ELF 64-bit LSB executable, x86-64, version 1 (SYSV),
源码: https://github.com/util-linux/util-linux/blob/master/login-utils/login.c (util-linux工具套件)
下面在agetty.c 和login.c中都会调用get_terminal_name得到,但是它只验证而已,他们最终会调用内核定义的三个宏。
/sbin/agetty main{ parse_args(argc, argv, &options); } parse_args(){ ... if (strcmp(op->tty, "-") == 0) { op->tty_is_stdin = 1; int fd = get_terminal_name(NULL, &op->tty, NULL); if (fd < 0) { log_warn(_("could not get terminal name: %d"), fd); //不能得到终端的名称 } } .... } // /bin/login static void init_tty(struct login_context *cxt){ get_terminal_name(&cxt->tty_path, &cxt->tty_name, &cxt->tty_number); }
https://kernel.googlesource.com/pub/scm/utils/util-linux/util-linux/+/master/lib/ttyutils.c
agetty.c中关于tty处理部分
/* Set up tty as stdin, stdout & stderr. */ static void open_tty(const char *tty, struct termios *tp, struct options *op) { .... }
//默认tty名是tty1
/etc/systemd/logind.conf
这个配置文件很重要的一个作用就是控制终端的实例数量。
centos7开始可以在 /etc/systemd/logind.conf 修改,文件/etc/systemd/logind.conf_是服务的配置文件systemd-logind, 服务管理命令为 systemd-logind.service 通过 cat /usr/lib/systemd/system/systemd-logind.service 查看启动服务文件,同时使用
systemctl restart systemd-logind
进行服务重启等。
[root@aozhejin2 ~]$file /usr/lib/systemd/systemd-logind
/usr/lib/systemd/systemd-logind: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV),
[root@aozhejin2 ~]$cat /etc/systemd/logind.conf # This file is part of systemd.#显示的值是编译到可执行文件中的默认值 # You can change settings by editing this file. # Defaults can be restored by simply deleting this file. # See logind.conf(5) for details. [Login] #NAutoVTs=6 //终端可以有几个,比如只能有3个终端,则设置为3 #ReserveVT=6 //要保留的VT,列表 #KillUserProcesses=no #KillOnlyUsers= #KillExcludeUsers=root #InhibitDelayMaxSec=5
#下面是电源管理命令,控制比如闲置怎么处理、合上盖子怎么处理等 #HandlePowerKey=poweroff #HandleSuspendKey=suspend #HandleHibernateKey=hibernate #HandleLidSwitch=suspend #合上笔记本还能运行,那么就启用它,当然它的值还可以是ignore #HandleLidSwitchDocked=ignore #PowerKeyIgnoreInhibited=no #SuspendKeyIgnoreInhibited=no #HibernateKeyIgnoreInhibited=no #LidSwitchIgnoreInhibited=yes #IdleAction=ignore #IdleActionSec=30min #RuntimeDirectorySize=10% #RemoveIPC=no #UserTasksMax=
查看下 systemd-logind 启动情况
[root@aozhejin2 ~]$systemctl status systemd-logind ● systemd-logind.service - Login Service Loaded: loaded (/usr/lib/systemd/system/systemd-logind.service; static; vendor preset: disabled) Active: active (running) since Wed 2023-03-29 17:45:37 CST; 23h ago Docs: man:systemd-logind.service(8) man:logind.conf(5) http://www.freedesktop.org/wiki/Software/systemd/logind http://www.freedesktop.org/wiki/Software/systemd/multiseat Main PID: 9448 (systemd-logind) Status: "Processing requests..." Tasks: 1 Memory: 3.4M CGroup: /system.slice/systemd-logind.service └─9448 /usr/lib/systemd/systemd-logind Mar 29 17:45:37 aozhejin2 systemd-logind[9448]: New session 57949 of user root. Mar 29 17:45:37 aozhejin2 systemd-logind[9448]: New session 1 of user root. Mar 29 17:45:37 aozhejin2 systemd-logind[9448]: New session 1057 of user root. Mar 29 18:08:07 aozhejin2 systemd-logind[9448]: Removed session 57949. ...
我们一下这个进程会打开哪些文件
[root@aozhejin2 ~]$lsof -p 9448 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME systemd-l 9448 root cwd DIR 253,0 4096 128 / systemd-l 9448 root rtd DIR 253,0 4096 128 / systemd-l 9448 root txt REG 253,0 639832 402655657 /usr/lib/systemd/systemd-logind systemd-l 9448 root mem REG 253,0 61560 269462479 /usr/lib64/libnss_files-2.17.so systemd-l 9448 root mem REG 253,0 19896 268991954 /usr/lib64/libattr.so.1.1.0 systemd-l 9448 root mem REG 253,0 19248 268820392 /usr/lib64/libdl-2.17.so systemd-l 9448 root mem REG 253,0 402384 268730267 /usr/lib64/libpcre.so.1.2.0 systemd-l 9448 root mem REG 253,0 2156592 268633378 /usr/lib64/libc-2.17.so systemd-l 9448 root mem REG 253,0 142144 269462486 /usr/lib64/libpthread-2.17.so systemd-l 9448 root mem REG 253,0 88720 268633409 /usr/lib64/libgcc_s-4.8.5-20150702.so.1 systemd-l 9448 root mem REG 253,0 37064 268991961 /usr/lib64/libacl.so.1.1.0 systemd-l 9448 root mem REG 253,0 20048 268991956 /usr/lib64/libcap.so.2.22 systemd-l 9448 root mem REG 253,0 43712 269462491 /usr/lib64/librt-2.17.so systemd-l 9448 root mem REG 253,0 155744 268633517 /usr/lib64/libselinux.so.1 systemd-l 9448 root mem REG 253,0 163312 281915295 /usr/lib64/ld-2.17.so systemd-l 9448 root 0r CHR 1,3 0t0 1028 /dev/null systemd-l 9448 root 1u unix 0xffff8a6de94f5500 0t0 640028488 socket systemd-l 9448 root 2u unix 0xffff8a6de94f5500 0t0 640028488 socket systemd-l 9448 root 3u unix 0xffff8a69cc137700 0t0 640029131 socket systemd-l 9448 root 4u a_inode 0,10 0 8534 [eventpoll] systemd-l 9448 root 5u a_inode 0,10 0 8534 [timerfd] systemd-l 9448 root 6r REG 0,18 4096 28661 /sys/devices/virtual/tty/tty0/active systemd-l 9448 root 7u a_inode 0,10 0 8534 [signalfd] systemd-l 9448 root 8u netlink 0t0 640029133 KOBJECT_UEVENT systemd-l 9448 root 9u netlink 0t0 640029134 KOBJECT_UEVENT systemd-l 9448 root 10u netlink 0t0 640029135 KOBJECT_UEVENT systemd-l 9448 root 11u netlink 0t0 640029136 KOBJECT_UEVENT systemd-l 9448 root 12u unix 0xffff8a69cc135500 0t0 640029137 socket systemd-l 9448 root 13u a_inode 0,10 0 8534 [timerfd] systemd-l 9448 root 14u CHR 13,64 0t0 1149 /dev/input/event0 systemd-l 9448 root 15r FIFO 0,20 0t0 640056595 /run/systemd/sessions/57961.ref systemd-l 9448 root 16u CHR 4,6 0t0 1048 /dev/tty6 systemd-l 9448 root 17r FIFO 0,20 0t0 640217015 /run/systemd/sessions/57980.ref systemd-l 9448 root 18r FIFO 0,20 0t0 641501820 /run/systemd/inhibit/1.ref
我们跟踪一下
[root@aozhejin2 ~]$strace -e open lsof -p 9448
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 open("/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3 open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 open("/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC) = 3 open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3 open("/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3 open("/proc/filesystems", O_RDONLY) = 3 open("/dev/null", O_RDWR) = 3 open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 open("/", O_RDONLY) = 3 open("/proc/98712/fdinfo/3", O_RDONLY) = 4 open("/proc/mounts", O_RDONLY) = 3 .... open("/proc/126121/stat", O_RDONLY) = 4 open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 4 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4 open("/lib64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 4 open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 4 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME open("/usr/lib64/gconv/gconv-modules.cache", O_RDONLY) = 4 systemd-l 9448 root cwd DIR 253,0 4096 128 / systemd-l 9448 root rtd DIR 253,0 4096 128 / systemd-l 9448 root txt REG 253,0 639832 402655657 /usr/lib/systemd/systemd-logind systemd-l 9448 root mem REG 253,0 61560 269462479 /usr/lib64/libnss_files-2.17.so systemd-l 9448 root mem REG 253,0 19896 268991954 /usr/lib64/libattr.so.1.1.0 systemd-l 9448 root mem REG 253,0 19248 268820392 /usr/lib64/libdl-2.17.so systemd-l 9448 root mem REG 253,0 402384 268730267 /usr/lib64/libpcre.so.1.2.0 systemd-l 9448 root mem REG 253,0 2156592 268633378 /usr/lib64/libc-2.17.so systemd-l 9448 root mem REG 253,0 142144 269462486 /usr/lib64/libpthread-2.17.so systemd-l 9448 root mem REG 253,0 88720 268633409 /usr/lib64/libgcc_s-4.8.5-20150702.so.1 systemd-l 9448 root mem REG 253,0 37064 268991961 /usr/lib64/libacl.so.1.1.0 systemd-l 9448 root mem REG 253,0 20048 268991956 /usr/lib64/libcap.so.2.22 systemd-l 9448 root mem REG 253,0 43712 269462491 /usr/lib64/librt-2.17.so systemd-l 9448 root mem REG 253,0 155744 268633517 /usr/lib64/libselinux.so.1 systemd-l 9448 root mem REG 253,0 163312 281915295 /usr/lib64/ld-2.17.so systemd-l 9448 root 0r CHR 1,3 0t0 1028 /dev/null systemd-l 9448 root 1u unix 0xffff8a6de94f5500 0t0 640028488 socket systemd-l 9448 root 2u unix 0xffff8a6de94f5500 0t0 640028488 socket systemd-l 9448 root 3u unix 0xffff8a69cc137700 0t0 640029131 socket systemd-l 9448 root 4u a_inode 0,10 0 8534 [eventpoll] systemd-l 9448 root 5u a_inode 0,10 0 8534 [timerfd] systemd-l 9448 root 6r REG 0,18 4096 28661 /sys/devices/virtual/tty/tty0/active systemd-l 9448 root 7u a_inode 0,10 0 8534 [signalfd] systemd-l 9448 root 8u netlink 0t0 640029133 KOBJECT_UEVENT systemd-l 9448 root 9u netlink 0t0 640029134 KOBJECT_UEVENT systemd-l 9448 root 10u netlink 0t0 640029135 KOBJECT_UEVENT systemd-l 9448 root 11u netlink 0t0 640029136 KOBJECT_UEVENT systemd-l 9448 root 12u unix 0xffff8a69cc135500 0t0 640029137 socket systemd-l 9448 root 13u a_inode 0,10 0 8534 [timerfd] systemd-l 9448 root 14u CHR 13,64 0t0 1149 /dev/input/event0 systemd-l 9448 root 15r FIFO 0,20 0t0 640056595 /run/systemd/sessions/57961.ref systemd-l 9448 root 16u CHR 4,6 0t0 1048 /dev/tty6 systemd-l 9448 root 17r FIFO 0,20 0t0 640217015 /run/systemd/sessions/57980.ref systemd-l 9448 root 18r FIFO 0,20 0t0 641501820 /run/systemd/inhibit/1.ref --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=98713, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
注意: 上面黄色显示的tty0代表当前,你可以通过读取 /sys/devices/virtual/tty/tty0/active 得到当前的tty
具体可以参看看 https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-tty
我的另一篇博文也有对于查看当前tty的阐述,https://www.cnblogs.com/aozhejin/p/17253982.html
我们继续分析下/sbin/init
[root@aozhejin2 ~]$ps xawf -eo pid,user,cgroup,args PID USER CGROUP COMMAND ...... 1144 root 11:pids:/lxc/mylxc,10:memor \_ /sbin/init 1182 root 11:pids:/user.slice,10:memo \_ /usr/lib/systemd/systemd-logind 1184 dbus 11:pids:/user.slice,10:memo \_ /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation 1188 root 11:pids:/user.slice,10:memo \_ /usr/sbin/crond -n 1369 root 11:pids:/user.slice,10:memo \_ /sbin/dhclient -1 -q -lf /var/lib/dhclient/dhclient--eth0.lease -pf /var/run/dhclient-eth0.pid -H mylxc.node eth0 1444 root 11:pids:/user.slice,10:memo \_ /usr/sbin/sshd -D 1445 root 11:pids:/user.slice,10:memo \_ /usr/sbin/rsyslogd -n 1894 root 11:pids:/user.slice,10:memo \_ login -- root 2153 root 11:pids:/user.slice,10:memo | \_ -bash 2151 root 11:pids:/user.slice,10:memo \_ /usr/lib/systemd/systemd-journald ....
显示键盘布局和系统本地化信息
[root@aozhejin2 ~]$localectl System Locale: LANG=en_US.UTF-8 VC Keymap: us X11 Layout: us
当前内核设置的
[root@aozhejin2 ~]$cat /sys/class/tty/console/active
0
/var/run/utmp文件 (登录日志)
[root@aozhejin2 ~]$cat /var/run/utmp #不正确 [root@aozhejin2 ~]$ last -f /var/run/utmp root pts/9 192.168.1.3 Thu Mar 30 19:09 still logged in root pts/8 192.168.1.3 Thu Mar 30 19:01 still logged in root pts/7 192.168.1.3 Fri Mar 31 09:26 still logged in reboot system boot 3.10.0-1160.62.1 Thu Apr 21 08:57 - 09:31 (344+00:33) utmp begins Thu Apr 21 08:57:37 2022
查看tty1服务...
[root@aozhejin2 ~]$systemctl status getty@tt1.service ● getty@tt1.service - Getty on tt1 Loaded: loaded (/usr/lib/systemd/system/getty@.service; enabled; vendor preset: enabled) Active: inactive (dead) Docs: man:agetty(8) man:systemd-getty-generator(8) http://0pointer.de/blog/projects/serial-console.html
/usr/lib/systemd/system/getty@.service
[root@aozhejin2 ~]$cat /usr/lib/systemd/system/getty@.service # This file is part of systemd. # # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. [Unit] Description=Getty on %I Documentation=man:agetty(8) man:systemd-getty-generator(8) Documentation=http://0pointer.de/blog/projects/serial-console.html After=systemd-user-sessions.service plymouth-quit-wait.service getty-pre.target After=rc-local.service # If additional gettys are spawned during boot then we should make # sure that this is synchronized before getty.target, even though # getty.target didn't actually pull it in. Before=getty.target IgnoreOnIsolate=yes # On systems without virtual consoles, don't start any getty. Note # that serial gettys are covered by serial-getty@.service, not this # unit. ConditionPathExists=/dev/tty0 [Service] # the VT is cleared by TTYVTDisallocate ExecStart=-/sbin/agetty --noclear %I $TERM Type=idle Restart=always RestartSec=0 UtmpIdentifier=%I TTYPath=/dev/%I TTYReset=yes TTYVHangup=yes TTYVTDisallocate=yes KillMode=process IgnoreSIGPIPE=no SendSIGHUP=yes # Unset locale for the console getty since the console has problems # displaying some internationalized messages. Environment=LANG= LANGUAGE= LC_CTYPE= LC_NUMERIC= LC_TIME= LC_COLLATE= LC_MONETARY= LC_MESSAGES= LC_PAPER= LC_NAME= LC_ADDRESS= LC_TELEPHONE= LC_MEASUREMENT= LC_IDENTIFICATION= [Install] WantedBy=getty.target DefaultInstance=tty1 //默认实例是tty1
查看一下 agetty进程,启动服务文件看上面,我们看到下面的都是1进程启用的
第二个参数 tty1,传递给agetty,main函数处理,利用parse_args、 open_tty等函数。
[root@aozhejin2 ~]$ps -ef | grep tty root 870 1 0 2022 tty1 00:00:00 /sbin/agetty --noclear tty1 linux root 11005 10876 0 18:08 pts/6 00:00:00 grep --color=auto tty root 104003 1 0 Mar25 tty6 00:00:00 /sbin/agetty --noclear tty6 linux
agetty.c 处理 termio 部分在termio_init中
/* Initialize termios settings. */ static void termio_init(struct options *op, struct termios *tp) { .... }
三、agetty的配置文件
agetty读取/etc/login.defs配置文件(参见 login.defs(5))。请注意,配置文件可能是与另一个包一起分发(通常是 shadow-utils)。
https://man7.org/linux/man-pages/man5/login.defs.5.html
本机 /etc/login.defs(工作在pam模式下,属于shadow password套件,所以这里可以忽略)
[root@aozhejin2 /usr/local/src/stracetest]$cat /etc/login.defs # 请注意,此配置文件中的参数控制shadow-utils组件中工具的行为.
# 这些工具都不使用PAM机制,因此应该在其他地方配置使用PAM的实用程序(如passwd命令)。 # 了解更多信息请参考 /etc/pam.d/system-auth等. # *REQUIRED* # Directory where mailboxes reside, _or_ name of file, relative to the # home directory. If you _do_ define both, MAIL_DIR takes precedence. # QMAIL_DIR is for Qmail #QMAIL_DIR Maildir MAIL_DIR /var/spool/mail #MAIL_FILE .mail # Password控制: # PASS_MAX_DAYS 密码可以使用的最大天数 # PASS_MIN_DAYS 密码更改之间允许的最小天数. # PASS_MIN_LEN 可接受的最小密码长度。 # PASS_WARN_AGE 密码过期前发出警告的天数。 PASS_MAX_DAYS 99999 PASS_MIN_DAYS 0 PASS_MIN_LEN 5 PASS_WARN_AGE 7 # useradd 中自动选择 uid 的最小/最大值 UID_MIN 1000 UID_MAX 60000 # 系统帐户 SYS_UID_MIN 201 SYS_UID_MAX 999 # groupadd中自动gid选择的最小/最大值 GID_MIN 1000 GID_MAX 60000 # 系统帐户 SYS_GID_MIN 201 SYS_GID_MAX 999 # 如果已定义,则在删除用户时运行此命令. # 它应该删除任何at/cron/print 作业等. 由要删除的用户所有(作为第一个参数传递)。 # USERDEL_CMD /usr/sbin/userdel_local #这个文件可以不存在 # 如果useradd在RH系统上默认为用户创建主目录,我们会这样做。这个选项在useradd命令行上被-m标志覆盖。 CREATE_HOME yes # 权限掩码已初始化为此值. 如果未指定,则权限掩码将初始化为022。 UMASK 077 # 这使得userdel能够在不存在成员的情况下删除用户组。 USERGROUPS_ENAB yes #使用 SHA512 加密密码。
/etc/login.defs被定义在util-linux套件里面的下面文件中
https://kernel.googlesource.com/pub/scm/utils/util-linux/util-linux/+/master/include/pathnames.h
https://github.com/mmalecki/util-linux/blob/master/login-utils/logindefs.c 中定义 getlogindefs_bool 函数
agetty.c会调用 getlogindefs_bool("LOGIN_PLAIN_PROMPT", 0) 检测
该文件针对 shadow password(非pam认证模式)
可参看 https://help.adelielinux.org/html/admin/config.html(相关和登录有关的配置文件)
解析 /etc/issue(这个通常也是login banner头)
[root@aozhejin2 ~]$agetty -N8nl /bin/true -f <(sed "s@\\l@$(tty |sed 's:^/dev/::')@g" /etc/issue) - CentOS Linux 7 (Core) Kernepts/6 3.10.0-1160.62.1.el7.x86_64 on an x86_64
[root@aozhejin2 ~]$cat /etc/issue
\S
Kernel \r on an \m
agetty.c中 read_os_release 负责解析 S //读取的 /etc/os-release 数据...
agetty.c 中
系统状态文件 | 注意事项 | |
/etc/issue | 打印登录之前的信息 | |
/etc/os-release /usr/lib/os-release | 操作系统标识数据 | |
/dev/console | 问题报告(if syslog(3) is not used) | |
/etc/inittab | /sbin/init配置文件,针对SysV-style init 守护进程 | systemd使用时,不读取/etc/inittab |
/var/run/utmp |
四、login.c(对应/bin/login)
我们下面做一个测试修改欢迎信息
//login.c 中设置的逻辑
main(){
...
initialize(argc, argv, &cxt); //这个函数里面调用 display_login_messages
...
} static void display_login_messages(void) { ... motd(); ... } static void motd(void) { //_PATH_MOTDFILE这个宏是在 // pathnames.h 中定义 } //pathnames.h #define _PATH_MOTDFILE "/usr/share/misc/motd:/run/motd:/etc/motd"
修改文件之后.重新登录
[root@aozhejin2 /etc/pam.d]$cat /etc/motd 欢迎你 root@192.168.1.2's password: Last login: Wed Mar 29 18:11:39 2023 from 10.129.55.19 欢迎你
五、PAM身份认证(这里不做介绍)
/bin/login 会调用相关pam设置 。 基于目录的配置 /etc/pam.d/都在这里
六、我们分析下内核启动时候的调用
E:\linux内核\linux-2.6.38.5\linux-2.6.38.5\init\main.c 内核启动入口
//汇编.S会调用这里 asmlinkage void __init start_kernel(void) { //最后调用 rest_init(); } static noinline void __init_refok rest_init(void) { //调用kernel_init kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); } //kernel_init定义 static int __init kernel_init(void * unused) { /* Open the /dev/console on the rootfs, this should never fail */ if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) printk(KERN_WARNING "Warning: unable to open an initial console.\n"); //执行/sbin/init等程序 init_post(); } //执行根文件系统下的 /sbin/init 等程序 static noinline int init_post(void) { /* need to finish all async __init code before freeing the memory */ async_synchronize_full(); free_initmem(); mark_rodata_ro(); system_state = SYSTEM_RUNNING; numa_default_policy(); current->signal->flags |= SIGNAL_UNKILLABLE; if (ramdisk_execute_command) { run_init_process(ramdisk_execute_command); printk(KERN_WARNING "Failed to execute %s\n", ramdisk_execute_command); } /* * We try each of these until one succeeds. * * The Bourne shell can be used instead of init if we are * trying to recover a really broken machine. */ if (execute_command) { run_init_process(execute_command); printk(KERN_WARNING "Failed to execute %s. Attempting " "defaults...\n", execute_command); } run_init_process("/sbin/init"); //这里内核代码2.6、3.10等都没有变化对于这里的,但是兼容systemd等。 run_init_process("/etc/init"); run_init_process("/bin/init"); run_init_process("/bin/sh"); panic("No init found. Try passing init= option to kernel. " "See Linux Documentation/init.txt for guidance."); } static void run_init_process(const char *init_filename) { argv_init[0] = init_filename; kernel_execve(init_filename, argv_init, envp_init); }
七、关于/sbin/init
Linux内核初始化(dmesg 命令查看内核启动日志或 /dev/kmsg,打印的都是内核调用的信息)完成后,内核调用执行程序/sbin/init。(对于 systemd来说,/sbin/init 实际上是指向另一个文件 /usr/lib/systemd/systemd 的符号链接(内核2.6、3.10、4.2、5.10等都是这样做到了先后兼容性处理,起码我看过内核源码是这样)
[root@aozhejin2 /]$readlink /sbin/init
../lib/systemd/systemd
[root@aozhejin2 /]$file /sbin/init
/sbin/init: symbolic link to `../lib/systemd/systemd'
//stat比较一下 /sbin/init和/usr/lib/systemd/systemd
[root@aozhejin2 /]$stat /sbin/init
File: â/sbin/initâ -> â../lib/systemd/systemdâ
Size: 22 Blocks: 0 IO Block: 4096 symbolic link
Device: fd00h/64768d Inode: 268956188 Links: 1
Access: (0777/lrwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2023-03-29 13:33:50.272887394 +0800
Modify: 2022-04-11 14:50:59.063110982 +0800
Change: 2022-04-11 14:50:59.064110982 +0800
Birth: -
[root@aozhejin2 /]$stat /usr/lib/systemd/systemd
File: â/usr/lib/systemd/systemdâ
Size: 1632960 Blocks: 3192 IO Block: 4096 regular file
Device: fd00h/64768d Inode: 402655640 Links: 1
Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2023-03-29 13:33:50.272887394 +0800
Modify: 2022-01-14 00:54:56.000000000 +0800
Change: 2022-04-11 14:50:58.678111000 +0800
查看/usr/lib/systemd/systemd这个文件是一个二进制文件
[root@aozhejin2 /]$file /usr/lib/systemd/systemd
/usr/lib/systemd/systemd: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), ....
我们看下init进程和 进程号为1的进程(启动进程的情况)
[root@aozhejin2 /usr/local/src/stracetest]$ps 1
PID TTY STAT TIME COMMAND
1 ? Ss 154:01 /usr/lib/systemd/systemd --system --deserialize 20
[root@aozhejin2 /usr/local/src/stracetest]$ps -ef | grep /sbin/init
root 1144 1135 0 2022 ? 00:01:21 /sbin/init
/sbin/init配置文件为 /etc/inittab,在linux启动时候读取
讲/sbin/init配置文件 即在解说systemd配置文件(本机采用systemd管理服务)
init 的 systemd 版本从 /etc/systemd/system目录 和 /usr/lib/systemd/system目录读取一系列文件。这些文件中的每一个都称为“单元”,单元可以是各种类型,例如服务、目标等,如文件名后缀(.service、.target 等)所示。“服务”通常是守护进程在后台运行以执行某些系统功能
systemd相关 | |
/usr/lib/systemd/system | systemd的服务 *.service、*.target等文件放置的目录 |
/etc/systemd/system | systemd本身配置文件 |
/usr/lib/systemd/systemd | /sbin/init指向该程序 |
systemd本身的配置文件放置目录
[root@aozhejin2 /]$ls /etc/systemd/system basic.target.wants default.target.wants local-fs.target.wants remote-fs.target.wants
sysinit.target.wants timers.target.wants default.target getty.target.wants multi-user.target.wants sockets.target.wants
system-update.target.wants
systemd二进制程序放置的目录以及启动服务放置的目录
[root@aozhejin2 /]$ls -l /usr/lib/systemd/
total 7960
drwxr-xr-x. 2 root root 4096 Apr 11 2022 catalog
-rw-r--r-- 1 root root 9551 Jan 14 2022 import-pubring.gpg
drwxr-xr-x. 2 root root 47 Jan 14 2022 ntp-units.d
......
drwxr-xr-x 2 root root 29 Nov 19 2021 scripts
drwxr-xr-x. 26 root root 16384 Mar 17 08:59 system // systemd的服务 *.service、*.target等文件放置的目录
-rwxr-xr-x 1 root root 1632960 Jan 14 2022 systemd // systemd的二进制程序
-rwxr-xr-x 1 root root 23968 Jan 14 2022 systemd-ac-power
-rwxr-xr-x 1 root root 70168 Jan 14 2022 systemd-activate
.....
-rwxr-xr-x 1 root root 317272 Jan 14 2022 systemd-initctl
-rwxr-xr-x 1 root root 346168 Jan 14 2022 systemd-journald
-rwxr-xr-x 1 root root 384224 Jan 14 2022 systemd-localed
-rwxr-xr-x 1 root root 639832 Jan 14 2022 systemd-logind
-rwxr-xr-x 1 root root 493576 Jan 14 2022 systemd-machined
-rwxr-xr-x 1 root root 53440 Jan 14 2022 systemd-machine-id-commit
-rwxr-xr-x 1 root root 66360 Jan 14 2022 systemd-modules-load
-rwxr-xr-x 1 root root 187536 Jan 14 2022 systemd-pull
.....
-rwxr-xr-x 1 root root 150280 Jan 14 2022 systemd-shutdown
-rwxr-xr-x 1 root root 66072 Jan 14 2022 systemd-shutdownd
-rwxr-xr-x 1 root root 91296 Jan 14 2022 systemd-sleep
-rwxr-xr-x 1 root root 108048 Jan 14 2022 systemd-socket-proxyd
-rwxr-xr-x 1 root root 66384 Jan 14 2022 systemd-sysctl
lrwxrwxrwx 1 root root 24 Sep 23 2021 systemd-sysv-install -> ../../..//sbin/chkconfig
-rwxr-xr-x 1 root root 384928 Jan 14 2022 systemd-timedated
-rwxr-xr-x 1 root root 416200 Jan 14 2022 systemd-udevd
上面删减了很多。。
Linux内核初始化完成后,init脚本执行程序/sbin/init。
简单回顾下SysV模式下 ,SysV的 /sbin/init 读取文件/etc/inittab,它决定了要运行的一系列脚本以完成初始化过程:
- init 运行的第一个脚本是 /etc/rc.d/rc.sysinit。该脚本执行多项任务。
- init 所做的下一件事是运行 /etc/rc.d/rc(N).d,并向其传递一个称为运行级别的数字。某些运行级别是标准的:
0 = 暂停
1 = 单用户模式
6 = 重启//看下我系统里面的目录
[root@aozhejin2 /]$ls /etc/rc.d/ init.d rc0.d rc1.d rc2.d rc3.d rc4.d rc5.d rc6.d rc.local运行级别 2-5 用于各种形式的多用户模式;这些运行级别的确切含义因发行版而异。
初始运行级别在 /etc/inittab 中指定。
下面看下本机注意: 当您使用systemd时候就不再使用inittab 即 /etc/initab 来init 初始化,而转交给了systemd管理系统
[root@aozhejin2 /usr/local/src/stracetest]$cat /etc/inittab
# 当使用systemd时候,inittab不再使用. (英文原文就是明确备注的 ) # ADDING CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM. # Ctrl-Alt-Delete 快捷键由 /usr/lib/systemd/system/ctrl-alt-del.target 这个来处理 # systemd 使用 'targets' 代替 runlevels. 默认的情况下有两个 main targets: # 1.multi-user.target: 类似于runlevel 3 # 2.graphical.target: 类似于runlevel 5 # 浏览默认的请运行,下面的命令: # systemctl get-default # 设置为默认的target,请运行下面命令: # systemctl set-default TARGET.target
[root@aozhejin2 /usr/local/src/stracetest]$cat /usr/lib/systemd/system/ctrl-alt-del.target # 这个文件是systemd的一部分分. # systemd is free software; you can redistribute it and/or modify it [Unit] Description=Reboot Documentation=man:systemd.special(7) DefaultDependencies=no Requires=systemd-reboot.service After=systemd-reboot.service AllowIsolate=yes JobTimeoutSec=30min JobTimeoutAction=reboot-force [Install] Alias=ctrl-alt-del.target
运行systemctl get-default
[root@aozhejin2 /usr/lib/systemd/system]$systemctl get-default multi-user.target
运行 systemctl set-default graphical.target (target位于/usr/lib/systemd/system/下) 重新设置
八、启动agtty
1. 通过 getty@.service 启动
[root@aozhejin2 /usr/lib/systemd/system]$cat getty@.service # This file is part of systemd. # version 2.1 of the License, or (at your option) any later version. [Unit] Description=Getty on %I Documentation=man:agetty(8) man:systemd-getty-generator(8) Documentation=http://0pointer.de/blog/projects/serial-console.html After=systemd-user-sessions.service plymouth-quit-wait.service getty-pre.target After=rc-local.service #如果在引导过程中产生了额外的getty,那么我们应该确保在getty.target之前同步,即使getty.target实际上并没有将其引入。 Before=getty.target IgnoreOnIsolate=yes # On systems without virtual consoles, don't start any getty. Note # that serial gettys are covered by serial-getty@.service, not this # unit. ConditionPathExists=/dev/tty0 [Service] # the VT is cleared by TTYVTDisallocate ExecStart=-/sbin/agetty --noclear %I $TERM #这里%I即tty1默认 Type=idle Restart=always RestartSec=0 UtmpIdentifier=%I TTYPath=/dev/%I TTYReset=yes TTYVHangup=yes TTYVTDisallocate=yes KillMode=process IgnoreSIGPIPE=no SendSIGHUP=yes # Unset locale for the console getty since the console has problems # displaying some internationalized messages. Environment=LANG= LANGUAGE= LC_CTYPE= LC_NUMERIC= LC_TIME= LC_COLLATE= LC_MONETARY= LC_MESSAGES= LC_PAPER= LC_NAME= LC_ADDRESS= LC_TELEPHONE= LC_MEASUREMENT= LC_IDENTIFICATION= [Install] WantedBy=getty.target DefaultInstance=tty1
实际情况怎么样呢?我们看下
[root@aozhejin2 /usr/lib/systemd/system]$ps -ef | grep agetty
root 870 1 0 2022 tty1 00:00:00 /sbin/agetty --noclear tty1 linux
root 11148 1 0 Mar29 tty6 00:00:00 /sbin/agetty --noclear tty6 linux
看下agetty打开了什么文件
[root@aozhejin2 /usr/lib/systemd/system]$lsof -p 870 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME agetty 870 root cwd DIR 253,0 4096 128 / agetty 870 root rtd DIR 253,0 4096 128 / agetty 870 root txt REG 253,0 49640 268729668 /usr/sbin/agetty agetty 870 root DEL REG 253,0 268633371 /usr/lib/locale/locale-archive #多语言支持 agetty 870 root DEL REG 253,0 268729900 /usr/lib64/libnss_files-2.17.so;64071407 agetty 870 root DEL REG 253,0 268633379 /usr/lib64/libc-2.17.so;64071407 //glibc库 agetty 870 root DEL REG 253,0 268633367 /usr/lib64/ld-2.17.so;64071407 agetty 870 root 0u CHR 4,1 0t0 1043 /dev/tty1 #标准输入 agetty 870 root 1u CHR 4,1 0t0 1043 /dev/tty1 #标准输出 agetty 870 root 2u CHR 4,1 0t0 1043 /dev/tty1 #标准错误
[root@aozhejin2 /usr/lib/systemd/system]$file /usr/lib/locale/locale-archive
/usr/lib/locale/locale-archive: PDP-11 separate I&D executable not stripped
请参看: https://man7.org/linux/man-pages/man1/localedef.1.html
https://manpages.courier-mta.org/htmlman7/locale.7.html
查看由systemd管理的 getty@tty1.service 服务启动的agetty,我们看到pid=870 是启动的agetty实例
[root@aozhejin2 /usr/lib/systemd/system]$ systemctl status getty@tty1.service ● getty@tty1.service - Getty on tty1 Loaded: loaded (/usr/lib/systemd/system/getty@.service; enabled; vendor preset: enabled) Active: active (running) since Thu 2022-04-21 08:57:47 CST; 11 months 7 days ago Docs: man:agetty(8) man:systemd-getty-generator(8) http://0pointer.de/blog/projects/serial-console.html Main PID: 870 (agetty) CGroup: /system.slice/system-getty.slice/getty@tty1.service └─870 /sbin/agetty --noclear tty1 linux 启动命令 Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.
因为有两个tty,所以查看另一个
[root@aozhejin2 /usr/lib/systemd/system]$ systemctl status getty@tty6.service ● getty@tty6.service - Getty on tty6 Loaded: loaded (/usr/lib/systemd/system/getty@.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2023-03-29 18:10:31 CST; 13h ago Docs: man:agetty(8) man:systemd-getty-generator(8) http://0pointer.de/blog/projects/serial-console.html Main PID: 11148 (agetty) CGroup: /system.slice/system-getty.slice/getty@tty6.service └─11148 /sbin/agetty --noclear tty6 linux Mar 29 18:10:31 aozhejin2 systemd[1]: Started Getty on tty6.
但是这个tty6自动产生的,这个设备你删除不了,一删除它自动又重新生成,不信你测试一下,它是专门为agetty保留的,这样做是为了确保始终有办法获得文本登录。
2. 我们可以修改agetty启动参数,从而更有效的控制agetty的行为
修改getty@.service文件, 例如修改ExeStart这行: ExecStart=-/sbin/agetty -o '-p -- \\u' --noissue --noclear %I $TERM #--noissue参数表示不显示 /etc/issue文件内容 #--noclear表示提示前不要清除屏幕 重新启动 systemctl restart getty@tty1
九、/etc/nsswitch.conf
这里需要介绍一下这个问题,它是系统来说是一个很重要的文件,也可以认为是数据库。
我们利用strace命令继续在细致看下它的打开调用情况
[root@aozhejin2 ~]$strace -e open lsof -p 870 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 open("/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3 open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 open("/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC) = 3 open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3 open("/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3 open("/proc/filesystems", O_RDONLY) = 3 open("/dev/null", O_RDWR) = 3 open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 open("/", O_RDONLY) = 3 open("/proc/67162/fdinfo/3", O_RDONLY) = 4 open("/proc/mounts", O_RDONLY) = 3 open("/proc/locks", O_RDONLY) = 3 .... open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 4 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4 open("/lib64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 4 open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 4 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME open("/usr/lib64/gconv/gconv-modules.cache", O_RDONLY) = 4 agetty 870 root cwd DIR 253,0 4096 128 / agetty 870 root rtd DIR 253,0 4096 128 / agetty 870 root txt REG 253,0 49640 268729668 /usr/sbin/agetty agetty 870 root DEL REG 253,0 268633371 /usr/lib/locale/locale-archive agetty 870 root DEL REG 253,0 268729900 /usr/lib64/libnss_files-2.17.so;64071407 agetty 870 root DEL REG 253,0 268633379 /usr/lib64/libc-2.17.so;64071407 agetty 870 root DEL REG 253,0 268633367 /usr/lib64/ld-2.17.so;64071407 agetty 870 root 0u CHR 4,1 0t0 1043 /dev/tty1 agetty 870 root 1u CHR 4,1 0t0 1043 /dev/tty1 agetty 870 root 2u CHR 4,1 0t0 1043 /dev/tty1 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=67163, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- +++ exited with 0 +++
我们看到这个文件/etc/nsswitch.conf,它配置系统如何使用各种数据库和名称解析机制,什么意思呢?
我们参看 https://illumos.org/man/5/nsswitch.conf 我的系统里面 sss 它是由
本系统是由下面的.so共享库实现 [root@aozhejin2 ~]$ls /usr/lib64/libnss_sss.so.2
/usr/lib64/libnss_sss.so.2 |
下面就是这个文件的做过处理的 /etc/nsswitch.conf
[root@aozhejin2 ~]$cat /etc/nsswitch.conf # /etc/nsswitch.conf
#这个文件应该在开始时使用最常用的服务进行排序。 # The entry '[NOTFOUND=return]' means that the search for an # entry should stop if the search in the previous entry turned # up nothing. Note that if the search failed due to some other reason # (like no NIS server responding) then the search continues with the # next entry. # 有效的入口包括下面,他们都由不同的共享库实现 # nisplus Use NIS+ (NIS version 3) # nis Use NIS (NIS version 2), also called YP # dns Use DNS (Domain Name Service) # files Use the local files # db Use the local database (.db) files # compat Use NIS on compat mode # hesiod Use Hesiod for user lookups # [NOTFOUND=return] Stop searching if not found so far # To use db, put the "db" in front of "files" for entries you want to be looked up first in the databases # 例如: #passwd: db files nisplus nis #shadow: db files nisplus nis #group: db files nisplus nis passwd: files sss #对应/etc/passwd shadow: files sss #对应/etc/shadow group: files sss #initgroups: files
#表示系统首先尝试通过查询files(即 /etc/hosts)来解析主机名和IP地址,如果失败,接下来通过查询 DNS 服务器,最后通过查询 NIS+ hosts: files dns myhostname bootparams: nisplus [NOTFOUND=return] files ethers: files netmasks: files #由ifconfig使用 networks: files protocols: files rpc: files services: files sss netgroup: files sss publickey: nisplus automount: files aliases: files nisplus
本文件比较复杂,既有对应内部的库调用,也有对应文件使用等。
为了更说明问题,我们做个实验,linux中获取用户属性都是通过getpwnam来取得
首先看下 /bin/login二进制程序的源文件login.c中获取用户属性信息
static void log_audit(struct login_context *cxt, int status) { int audit_fd; struct passwd *pwd = cxt->pwd; audit_fd = audit_open(); if (audit_fd == -1) return; if (!pwd && cxt->username) pwd = getpwnam(cxt->username); audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN, NULL, "login", cxt->username ? cxt->username : "(unknown)", pwd ? pwd->pw_uid : (unsigned int)-1, cxt->hostname, NULL, cxt->tty_name, status); close(audit_fd); }
...
//当然login.c 还用到了pam模式
下面我们自己做下实验来看下
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <pwd.h> int main() { struct passwd *p; if((p = getpwnam("root")) != NULL) { printf("%s:",p->pw_name); printf("%s:\n",p->pw_passwd); printf("%u:\n",p->pw_uid); printf("%u:\n",p->pw_gid); printf("%s:\n",p->pw_gecos); printf("%s:\n",p->pw_dir); printf("%s\n",p->pw_shell); } } 编译 [root@ht8 c]# gcc getpwnam.c //没有指定名称,则自动产生a.out [root@ht8 c]# ./a.out root:x: 0: 0: root: /root: /bin/bash //我们看看她打开的文件 [root@ht8 c]# strace -e open ./a.out open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 //解析,这个文件很多命令都会用它 open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 #共享库缓存 //调用libnss库(它会去调glibc库,glibc的libc.so.6中定义了getpwnam) open("/lib64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 3 //解析 open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 3 root:x: 0: 0: root: /root: /bin/bash +++ exited with 10 +++
继续解释:
/etc/nsswitch.conf中的passwd是由getpwnam函数解析出来,
共享库缓存 /etc/ld.so.cache 由ldconfig命令来管理,为了减少共享库系统的库搜索时间,该命令用来刷新系统的共享库缓存 /etc/ld.so.cache 文件。 在安装新的共享库之后,一定要运行 ldconfig 刷新该缓存。
我们看下getpwnam定义在哪里
//这个函数并不再这里 [root@ht8 c]# objdump -tT /lib64/libnss_files.so.2 | grep getpwnam 0000000000005f00 g F .text 000000000000013b _nss_files_getpwnam_r 0000000000005f00 g DF .text 000000000000013b GLIBC_PRIVATE _nss_files_getpwnam_r //有三种方式可以寻找.so链接库内的函数列表 //nm -D /lib64/libnss_files.so.2 //objdump -tT /lib64/libnss_files.so.2 //继续找 /lib64/libnss_files.so.2 的依赖库 [root@ht8 c]# ldd /lib64/libnss_files.so.2 linux-vdso.so.1 => (0x00007fff07fee000) libc.so.6 => /lib64/libc.so.6 (0x00007f6b205a0000) // /lib64/ld-linux-x86-64.so.2 (0x00007f6b20b81000) //找到getpwnam,注意libc.so.6是C运行时库 glibc的软链接 [root@ht8 c]# nm -D /lib64/libc.so.6 | grep getpwnam 00000000000c42b0 T getpwnam 00000000000c48b0 T getpwnam_r [root@ht8 c]# readlink /lib64/libc.so.6 libc-2.17.so [root@ht8 c]# file /lib64/libc.so.6 /lib64/libc.so.6: symbolic link to `libc-2.17.so' //libc-2.17.so说明 2.1x表示其对应版本,去兼容相应CentOS版本
/lib64/libnss_files.so.2 会读取 /etc/passwd, /etc/group, /etc/hosts等文件,下面会具体给出哪些库实现了哪些source(nsswitch.conf中的定义叫source) 。
我们回过头来看下/etc/nsswitch.conf 里面的各个source由哪些共享库来实现的。
我们通过 ldconfig -p | grep nss_* 来在缓存 /etc/ld.so.cache中进行查找,注意ld.so.cache不能用cat 加管道的方式来匹配
本机64位,centos | |
共享库位置和名称 | source |
/usr/lib64/libnss_sss.so.2 | 实现 sss |
/usr/lib64/libnss_files-2.17.so | 实现 files |
/lib64/libnss_dns.so.2 | 实现dns |
/lib64/libnss_nis.so.2 | 实现nis |
/lib64/libnss_nisplus.so.2 | 实现nisplus |
本库本机没有安装 | 实现ldap |
这个部分放在这里实在是有点大,可以单独一篇博文,不过为了说明问题,和上面保持一个整体就先放这里。
十、systemd的登录配置文件
/etc/systemd/logind.conf
/etc/systemd/logind.conf.d/*.conf
/run/systemd/logind.conf.d/*.conf
/usr/lib/systemd/logind.conf.d/*.conf
get@.service的模板来自 autovt@.service
login.NAutoVTs 取一个正整数。配置默认分配多少个虚拟终端 (VT),当切换到这些虚拟终端且之前未使用时,“ autovt
”服务会自动生成。这些服务是从相应 VT TTY 名称的模板单元实例化的 autovt@.service
,例如,autovt@tty4.service
。默认情况下,autovt@.service
链接到 getty@.service
. 换句话说,登录提示是在用户切换到未使用的虚拟终端时动态启动的。因此,此参数控制多少登录“gettys
" 在 VT 上可用。如果某个 VT 已被某些其他子系统使用(例如,图形登录),则不会尝试这种激活。请注意,配置的 VT 始终受这种激活的影响 ReserveVT=
,即使它不是使用该指令配置的 VT 之一NAutoVTs=
。默认为 6。设置为 0 时,autovt
将禁用“”服务的自动生成。
[root@aozhejin2 /usr/lib/systemd/system]$cat /etc/systemd/logind.conf # This file is part of systemd. # Entries in this file show the compile time defaults. # You can change settings by editing this file. # Defaults can be restored by simply deleting this file. # See logind.conf(5) for details. [Login] NAutoVTs=3 #ReserveVT=6 #KillUserProcesses=no #KillOnlyUsers= #KillExcludeUsers=root .....
查看下systemd-logind状态信息
[root@aozhejin2 ~]$systemctl status systemd-logind ● systemd-logind.service - Login Service Loaded: loaded (/usr/lib/systemd/system/systemd-logind.service; static; vendor preset: disabled) Active: active (running) since Wed 2023-03-29 17:45:37 CST; 22h ago Docs: man:systemd-logind.service(8) man:logind.conf(5) http://www.freedesktop.org/wiki/Software/systemd/logind http://www.freedesktop.org/wiki/Software/systemd/multiseat Main PID: 9448 (systemd-logind) Status: "Processing requests..." Tasks: 1 Memory: 3.4M CGroup: /system.slice/systemd-logind.service └─9448 /usr/lib/systemd/systemd-logind Mar 29 17:45:37 aozhejin2 systemd-logind[9448]: New session 57949 of user root. Mar 29 17:45:37 aozhejin2 systemd-logind[9448]: New session 1 of user root. Mar 29 17:45:37 aozhejin2 systemd-logind[9448]: New session 1057 of user root. Mar 29 18:08:07 aozhejin2 systemd-logind[9448]: Removed session 57949. Mar 29 18:08:15 aozhejin2 systemd-logind[9448]: New session 57961 of user root. Mar 29 18:11:39 aozhejin2 systemd-logind[9448]: New session 57963 of user root. Mar 29 19:55:45 aozhejin2 systemd-logind[9448]: Removed session 57963. Mar 29 19:55:57 aozhejin2 systemd-logind[9448]: New session 57975 of user root. Mar 29 20:21:00 aozhejin2 systemd-logind[9448]: Removed session 57975. Mar 29 20:21:10 aozhejin2 systemd-logind[9448]: New session 57980 of user root. [root@aozhejin2 ~]$lsof -p 9448 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME systemd-l 9448 root cwd DIR 253,0 4096 128 / systemd-l 9448 root rtd DIR 253,0 4096 128 / systemd-l 9448 root txt REG 253,0 639832 402655657 /usr/lib/systemd/systemd-logind systemd-l 9448 root mem REG 253,0 61560 269462479 /usr/lib64/libnss_files-2.17.so systemd-l 9448 root mem REG 253,0 19896 268991954 /usr/lib64/libattr.so.1.1.0 systemd-l 9448 root mem REG 253,0 19248 268820392 /usr/lib64/libdl-2.17.so systemd-l 9448 root mem REG 253,0 402384 268730267 /usr/lib64/libpcre.so.1.2.0 systemd-l 9448 root mem REG 253,0 2156592 268633378 /usr/lib64/libc-2.17.so systemd-l 9448 root mem REG 253,0 142144 269462486 /usr/lib64/libpthread-2.17.so systemd-l 9448 root mem REG 253,0 88720 268633409 /usr/lib64/libgcc_s-4.8.5-20150702.so.1 systemd-l 9448 root mem REG 253,0 37064 268991961 /usr/lib64/libacl.so.1.1.0 systemd-l 9448 root mem REG 253,0 20048 268991956 /usr/lib64/libcap.so.2.22 systemd-l 9448 root mem REG 253,0 43712 269462491 /usr/lib64/librt-2.17.so systemd-l 9448 root mem REG 253,0 155744 268633517 /usr/lib64/libselinux.so.1 systemd-l 9448 root mem REG 253,0 163312 281915295 /usr/lib64/ld-2.17.so systemd-l 9448 root 0r CHR 1,3 0t0 1028 /dev/null systemd-l 9448 root 1u unix 0xffff8a6de94f5500 0t0 640028488 socket systemd-l 9448 root 2u unix 0xffff8a6de94f5500 0t0 640028488 socket systemd-l 9448 root 3u unix 0xffff8a69cc137700 0t0 640029131 socket systemd-l 9448 root 4u a_inode 0,10 0 8534 [eventpoll] systemd-l 9448 root 5u a_inode 0,10 0 8534 [timerfd] systemd-l 9448 root 6r REG 0,18 4096 28661 /sys/devices/virtual/tty/tty0/active systemd-l 9448 root 7u a_inode 0,10 0 8534 [signalfd] systemd-l 9448 root 8u netlink 0t0 640029133 KOBJECT_UEVENT systemd-l 9448 root 9u netlink 0t0 640029134 KOBJECT_UEVENT systemd-l 9448 root 10u netlink 0t0 640029135 KOBJECT_UEVENT systemd-l 9448 root 11u netlink 0t0 640029136 KOBJECT_UEVENT systemd-l 9448 root 12u unix 0xffff8a69cc135500 0t0 640029137 socket systemd-l 9448 root 13u a_inode 0,10 0 8534 [timerfd] systemd-l 9448 root 14u CHR 13,64 0t0 1149 /dev/input/event0 systemd-l 9448 root 15r FIFO 0,20 0t0 640056595 /run/systemd/sessions/57961.ref systemd-l 9448 root 16u CHR 4,6 0t0 1048 /dev/tty6 systemd-l 9448 root 17r FIFO 0,20 0t0 640217015 /run/systemd/sessions/57980.ref systemd-l 9448 root 18r FIFO 0,20 0t0 641501820 /run/systemd/inhibit/1.ref
十一个、添加一个新的tty(前提是该tty设备已存在)
1)添加新的 agetty:
在 /etc/systemd/system/getty.target.wants/ 添加新的软链接即可:
[root@aozhejin2 ~]$ln -sf /usr/lib/systemd/system/getty@.service /etc/systemd/system/getty.target.wants/getty@tty9.service
# systemctl start getty@tty9.service
2)移除 agetty:
从 /etc/systemd/system/getty.target.wants/ 删除多个对应的软链接即可:
# rm /etc/systemd/system/getty.target.wants/getty@tty9.service
# systemctl stop getty@tty9.service
[root@aozhejin2 /etc/systemd/system]$ps -ef | grep agetty root 870 1 0 2022 tty1 00:00:00 /sbin/agetty --noclear tty1 linux root 11148 1 0 Mar29 tty6 00:00:00 /sbin/agetty --noclear tty6 linux root 105876 1 0 19:00 tty9 00:00:00 /sbin/agetty --noclear tty9 linux
查看下打开的文件
[root@aozhejin.node ~]$lsof -p 105876 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME agetty 105876 root cwd DIR 253,0 4096 128 / agetty 105876 root rtd DIR 253,0 4096 128 / agetty 105876 root txt REG 253,0 49640 268729668 /usr/sbin/agetty agetty 105876 root mem REG 253,0 106176928 268633366 /usr/lib/locale/locale-archive agetty 105876 root mem REG 253,0 61560 269462479 /usr/lib64/libnss_files-2.17.so agetty 105876 root mem REG 253,0 2156592 268633378 /usr/lib64/libc-2.17.so agetty 105876 root mem REG 253,0 163312 281915295 /usr/lib64/ld-2.17.so agetty 105876 root 0u CHR 4,9 0t0 1051 /dev/tty9 agetty 105876 root 1u CHR 4,9 0t0 1051 /dev/tty9 agetty 105876 root 2u CHR 4,9 0t0 1051 /dev/tty9
把当前的tty设置为tty9
[root@aozhejin2 ~]$chvt 9 [root@aozhejin2 ~]$cat /sys/devices/virtual/tty/tty0/active tty9
参考资料:
https://man7.org/linux/man-pages/man8/agetty.8.html
https://www.oreilly.com/library/view/linux-in-a/0596000251/re01.html
https://www.physics.udel.edu/~bnikolic/teaching/phys660/RUTE/rute/node35.html
https://www.real-world-systems.com/docs/agetty.1.html agetty使用说明
https://linux.die.net/man/8/telinit
https://en.wikipedia.org/wiki/Computer_terminal
https://www.physics.udel.edu/~bnikolic/teaching/phys660/RUTE/rute/node35.html 应该意思到这里在说SysVinit
http://glennastory.net/boot/init.html
http://glennastory.net/boot/systemd.html
http://glennastory.net/boot/login.html
http://glennastory.net/boot/getty@.service.txt
http://glennastory.net/boot/ssh.service
http://glennastory.net/boot/startup.html
https://www.computernetworkingnotes.com/linux-tutorials/differences-between-sysvinit-upstart-and-systemd.html
https://bugzilla.redhat.com/show_bug.cgi?id=1123345
https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/ agtty下载
https://www.man7.org/linux/man-pages/man8/agetty.8.html#ISSUE_FILES /etc/issue文件讲解
https://grimoire.carcano.ch/blog/linux-console-essential-virtual-terminals-terminal-emulation-locale/
https://man7.org/linux/man-pages/man2/ioctl_tty.2.html
https://askubuntu.com/questions/902998/how-to-check-which-tty-im-currently-using
https://linux.die.net/man/3/stdout
https://linux.die.net/man/2/
https://linux.die.net/man/2/open
https://subscription.packtpub.com/book/cloud-and-networking/9781801811644/21/ch21lvl1sec85/understanding-logindconf
https://wizardforcel.gitbooks.io/vbird-linux-basic-4e/content/149.html
https://en.wikipedia.org/wiki/RS-232 串口端口
https://man7.org/linux/man-pages/man8/systemd-getty-generator.8.html
https://www.ibm.com/docs/en/aix/7.1?topic=t-tty-command tty命令使用
https://codebrowser.dev/glibc/glibc/sysdeps/unix/getlogin.c.html
https://kernel.googlesource.com/pub/scm/utils/util-linux/util-linux/+/master/lib/ttyutils.c
https://github.com/util-linux/util-linux/blob/master/include/ttyutils.h glibc
https://kernel.googlesource.com/pub/scm/utils/util-linux/util-linux/+/master util-linux套件源码
https://copyprogramming.com/howto/what-is-the-difference-between-stdin-and-stdin-fileno
http://www.compsci.hunter.cuny.edu/~sweiss/course_materials/unix_lecture_notes/chapter_04.pdf
https://www.thegeekdiary.com/understanding-etclogin-defs-file/
https://www.freedesktop.org/software/systemd/man/systemd.html#
https://forum.salixos.org/viewtopic.php?t=2590 自动登录
https://help.adelielinux.org/html/admin/config.html 与登录有关的配置文件
http://littlesvr.ca/linux-stuff/articles/autologinconsole/autologinconsole.php
https://www.freedesktop.org/software/systemd/man/logind.conf.html
http://0pointer.de/blog/projects/serial-console.html
https://ubuntuforums.org/showthread.php?t=2353287
https://docs.oracle.com/en/operating-systems/oracle-linux/6/admin/about-etc-nsswitch.html
https://www.qnx.com/developers/docs/6.5.0SP1.update/com.qnx.doc.neutrino_utilities/n/nsswitch.conf.html
https://illumos.org/man/5/nsswitch.conf
https://docs.oracle.com/cd/E19253-01/816-5174/nsswitch.conf-4/index.html files列表
https://www.real-world-systems.com/docs/agetty.1.html 设置/etc/issue
http://0pointer.de/blog/projects/systemd.html systemd原始设计文档
https://www.oreilly.com/library/view/network-security-hacks/0596006438/ch01s18.html
https://linux.die.net/man/5/login.defs
https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-tty
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?