Linux服务与安全管理
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.2 管理系统服务和进程

3.2.1 管理系统服务

举个简单的例子,“kudzu”是一个开机自动运行的脚本,它会自动检查系统中所有的硬件资料,生成“/etc/sysconfig/hwconf”文件。如果系统添加了新的硬件,需要让计算机自动识别的话,可使用命令“service kudzu start”。然而运行类似“kudzu”这样的服务很费时间,将这些服务关闭可以提高系统启动的效率。管理系统服务通常有以下几种方法。

1.chkconfig命令

若要查看kudzu的在0~7的各个运行级别上的启动状态,可参考图3-6中的步骤。

图3-6 查看kudzu服务的启动运行状态

若不指定服务名,运行“chkconfig --list | less”命令可以查看到所有系统服务和脚本在各个运行级别上的启动状态,如图3-7所示。

图3-7 查看所有服务的启动运行状态

Linux的服务分为两类:由系统初始化程序init启动的独立运行的服务和受超级进程xinetd管理的非独立运行的服务。xinetd本身也是一个独立运行的服务,默认在3~5号运行级别上开启,它负责管理系统中不频繁使用的服务,当这些子服务被请求时,由xinetd服务负责启动运行,完成服务请求后,再结束该服务的运行,以减少对系统资源的占用。因此,在管理这两种服务时存在一定差别。

(1)设置独立运行的服务的启动状态:

# chkconfig --level <运行级别列表> <服务名称> <on|off|reset>

命令功能:设置指定服务在指定运行级别中的启动状态。参数on代表设置为启动,off为不启动,reset代表恢复为系统的默认启动状态。

例如,在3号和4号运行级别上关闭独立服务kudzu,如图3-8所示。

图3-8 设置kudzu的启动运行状态

(2)设置非独立运行的服务的启动状态:

# chkconfig <服务名称> <on|off|reset>

非独立运行的服务受xinetd服务的管理,当启动状态改变后,需要重新启动xinetd服务,才能使设置立即生效。xinetd的子服务全部是默认关闭的。

例如,启动xinetd的子服务rsync,步骤如图3-9所示。

图3-9 设置“rsync”的启动运行状态

配置好后运行“reboot”重启计算机或者执行chkconfig命令,确认配置生效。

2.setup或者ntsysv工具

执行setup命令会运行一个基于文本界面的实用程序,操作简单直观,可以配置认证方法、防火墙、鼠标、网络服务、系统服务等,如图3-10所示;ntsysv的界面与setup相同,但仅能用来配置系统服务,如图3-11所示。与chkconfig不同的是,这两个工具只针对当前的运行级别进行调整。

图3-10 运行setup工具

图3-11 运行“ntsysv”工具

配置好后运行“reboot”重启计算机或者执行chkconfig命令,确认配置生效。

通过以上两种方式,可以使得Linux的服务在系统启动或进入某运行级别时会自动启动或停止。下面要介绍的另外两种方式,就是在系统运行的过程中,使用相应的命令来实现对某服务的启动、停止或重新启动。

3.服务启动脚本

什么是服务启动脚本呢?我们使用命令“ls -ld /etc/rc?.d”即可列出7个运行级别所对应的目录。实际上,每个目录都有一个符号链接,指向“/etc/rc.d/”目录,如图3-12所示。

图3-12 每个运行级别对应一个目录

子目录rc0.d~rc6.d分别存放了各运行级别的脚本。系统运行在哪个级别,就会进入相应的目录(建议参考“/etc/inittab”文件,该文件是系统初始化的主要配置文件),然后通过该目录下的脚本来决定启动或者不启动某项服务。如图3-13所示为RHEL 5“/etc/rc.d/rc3.d”目录的部分内容。

图3-13 “/etc/rc.d/rc3.d”目录中的脚本

可以看出,所有的服务启动脚本都放在“/etc/rc.d/init.d”目录中,而目录“/etc/rc.d/rcN.d”下的服务启动脚本文件都是链接到目录“/etc/rc.d/init.d/”的,该目录中有哪些脚本,与当前系统中所安装的服务有关。

那么为何在不同的运行级别下,系统默认会开启或者关闭特定的服务,并且会以固定的顺序来开启这些服务呢?这是以不同运行级别下服务脚本文件的命名方式来决定的。名字以S开头表示在相应的运行级别下默认启动,以K开头表示在相应的运行级别下默认不启动;之后接的两位数字表示启动的顺序,以解决各服务之间的依赖关系。例如,K02dhcdbd会先于K20nfs被执行;最后是要管理的服务的名称。

例如,要让一个程序在 Linux系统下一开机就启动,并且在关机前会自动结束,可以在目录“/etc/rc.d/init.d”下写一个script,并将其链接到特定的run-level目录(/etc/rc.d/rcN.d)下,这样就能随心所欲地控制该程序的启动与结束了。

Linux中使用chkconfig等工具可以使服务在系统启动或进入某运行级别时自动启动或停止,当然,我们还可以在系统运行过程中,使用命令来改变某服务的当前状态。用法如下:

# /etc/rc.d/init.d/服务启动脚本名 {start |stop |status |restart |condrestart |reload}

目录“/etc/rc.d/init.d/”是以rpm方式安装的服务的启动目录。例如,已知sendmail是以rpm方式安装的,则使用命令“/etc/rc.d/init.d/sendmail restart”就可以直接重新启动sendmail了。如图3-14所示为使用服务启动脚本管理xinetd服务的例子。

图3-14 使用服务启动脚本管理xinetd服务

4.service命令

RHEL专门提供了service命令来简化服务的管理,其用法如下:

# service 服务名称 {start|stop|restart}

用户在任何路径下均可通过该命令来管理服务,service命令会自动到“/etc/rc.d/init.d”目录中查找并执行相应的服务启动脚本。该命令完成后立刻生效。

例如,使用service命令管理xinetd服务更加简单方便,如图3-15所示。

图3-15 使用service命令管理xinetd服务

3.2.2 管理系统进程

1.进程与程序

Linux是一个多用户多任务的操作系统,Linux上每个用户的任务、每个系统管理的守护进程都可以称之为进程,系统是通过进程来完成工作的。Linux用分时管理的方法使所有的任务共享和使用系统资源。

那么进程和程序之间有何区别和联系呢?程序是静态保存在外部存储介质中的可执行代码和数据。进程是在处理器中动态执行的一个单独的程序。进程由程序产生,要占用系统运行资源,一个程序可以启动多个进程。进程是有生命状态的,进程状态分为:创建态、就绪态、运行态、结束。

Linux系统中所有进程都是相互联系的。除了初始化进程init外,所有进程都有父进程。每一个进程都有一个独立的进程号(PID),系统通过调用进程号来调度操控进程。Linux系统中所有的进程都是由PID固定为1的init进程衍生而来的。在Shell下执行程序启动的进程就是Shell进程的子进程,一般情况下,只有子进程结束后,才能继续父进程,若是从后台启动的,则不用等待子进程结束。可以使用pstree命令查看系统的进程树型结构,观察进程之间的父子关系。

2.进程的启动

在输入程序名来执行一个程序时,此时也就启动了一个进程。每个进程都有一个进程号,用于被系统识别和调度、管理。启动进程有两个主要途径,即手工启动和调度启动。

(1)手工启动。

由用户在shell命令行下输入要执行的程序来启动一个进程,即为手工启动进程,其启动方式又分为前台启动和后台启动,默认为前台启动,若在要执行的命令后面跟随一个“&”,则为后台启动,此时进程在后台运行,shell可继续运行和处理其他程序。例如:

# cp /dev/cdrom mycd.iso &                          // 将此cp任务交给后台执行

(2)调度启动。

在对Linux系统进行维护和管理的过程中,有时需要进行一些比较费时而且占用资源较多的操作,为不影响正常的服务,通常将其安排在深夜由系统自动运行,此时就可以采用下面两种调度启动方式,事先安排好任务运行的时间,到时系统就会自动完成指定的操作。

◇ at:在指定时刻执行指定的命令序列。

语法:# at time

说明:at命令允许使用一套相当复杂的时间指定方法。例如,指定在今天下午5:30执行某任务。假设现在是2011年6月3日中午12:30,则其命令格式可以如下:

at 5:30pm       at 17:30 at 17:30 today at now + 5 hours                
at now + 300 minutes at 17:30 9.10.10   at 17:30 10/9/10        at 17:30 Oct 9

输入回车后就进入了at的命令环境,在提示符“>”后输入要在该时间点执行的任务:

>mail –s "hello" teacher "It's my jobs"

at允许使用“-f”选项从指定的文件中读取需要定时执行的任务。例如:

$ at -f work 4pm + 3 days                               // 在三天后下午4点执行work中的任务
$ at < work 4pm + 3 days                             // 重定向输入,实现的功能同上

【范例】 找出系统中所有名字以.txt结尾的文件,并打印结果清单,然后给用户petcat发出邮件通知取件,指定任务的执行时间为2011年3月3日凌晨3:25。命令写法如图3-16所示。

图3-16 使用at命令

在此at任务中,root为用户petcat发送了一封邮件,下面进行验证,如图3-17所示。

图3-17 验证at任务的执行结果

◇ crontab:设置在系统中需要周期性完成的任务。

语法:

# crontab -l                                                    // 查看用户的cron任务
# crontab –e                                                    // 调用文本编辑器编辑用户的cron任务
# crontab –r                                                    // 删除用户现有的cron任务

说明:用于安装、删除或者列出用于驱动crond后台进程的表格。每个用户都有一个文件“/var/spool/cron/username”来保存自己的cron任务,该文件也叫做cron任务表。cron表中的前5个字段用来指定周期性的时间,最后一个字段指定在此周期性的时间点上要执行的任务(在多个命令之间可以用“;”分隔)。具体格式如下:

minute  hour    day     month   day of week     command

其中,指定时间的合法范围如下:

Minute                  00~59
Hour                    00~23,其中00点就是晚上12点
day-of-month    01~31
month-of-year   01~12
day-of-week             0~7,其中周日可以是0或者7

不能直接编辑文件“/var/spool/cron/username”的内容来建立用户的cron任务,而必须使用“crontab”命令来管理。此外,还有一个对于所有用户有效的文件“/etc/crontab”,它主要用来设置系统维护所需的例行性任务,一般无须修改。

【范例】 列出用户当前的cron任务表。

# crontab -l
10      6       *       *       *       date                    // 每天早上6:10执行“date”命令
0       */2     *       *       *       date                    // 每隔两小时整点执行“date”命令
0       1,3     *       *       5       date                    // 每周五1点和3点执行“date”命令

【范例】 用户root希望在每天凌晨发信给petcat,并且每隔两天在下午3∶00重启系统。

# crontab –e

回车后进入vi界面,编辑root的crontab 文件“/var/spool/cron/root”,形成如下的cron任务(注意,每项任务占用一行):

0       00      *       *       *               mail petcat</root/lover.txt
0       13      *       *       1,3,5   shutdown -r +5 "Reboot in 5 mins!"

3.管理系统的进程

我们依靠PID(进程号)来标识每个进程,因此对于进程的管理也离不开PID。下面我们使用ps与top这两个常用于观察系统进程工作状态的命令来具体地了解一下什么是进程。

(1)ps。

语法:# ps [options]

说明:显示当前时刻系统进程的状态信息,默认仅显示当前控制台的进程。常用参数有:

◇ u 输出进程用户所属的详细信息。

◇ a 显示系统中所有用户的进程。

◇ x 显示所有前台和后台进程。

【范例】 查看系统所有的进程。

# ps -aux
Warning: bad syntax, perhaps a bogus '-'? See /usr/share/doc/procps-3.2.7/FAQ
USER PID %CPU   %MEM VSZ RSS TTY        STAT START      TIME COMMAND
root 1    0.0    0.2     2040 640  ?     Ss      Mar02  0:01 init [3]
root 2    0.0    0.0        0  0  ?      S       Mar02  0:00 [migration/0]
root 3    0.0    0.0    0  0  ?          SN      Mar02  0:00 [ksoftirqd/0]
root 4    0.0    0.0        0  0  ?      S       Mar02  0:00 [watchdog/0]
……
root 2948 0.0    0.1     1636 436 tty2   Ss+     Mar02  0:00 /sbin/ mingetty
root 2949 0.0    0.1     1636 436 tty3   Ss+     Mar02  0:00 /sbin/ mingetty
root 2950 0.0    0.1     1636 432 tty4   Ss+     Mar02  0:00 /sbin/ mingetty
root 2951 0.0    0.1     1640 440 tty5   Ss+     Mar02  0:00 /sbin/ mingetty
root 2952 0.0    0.1     1636 436 tty6   Ss+     Mar02  0:00 /sbin/ mingetty
root 3003 0.0    0.5 4504 1420 tty1     Ss+       Mar0 20:00 -bash
root 4209 0.2    1.0 8996 2716   ?       Ss      01:38  0:00 sshd: root@pts/
root 4211 0.0    0.5          4500 1396 pts/0 Ss         01:38  0:00 -bash
root 4260 0.0    0.3          4228 932 pts/0 R+  01:40  0:00 ps -aux

在后面的服务器管理部分,我们经常会用到命令“ps -aux”列出所有信息以供自己检查进程的问题。下面是对执行结果中各个字段的说明。

◇ USER:进程的执行者。

◇ PID:进程的代号。

◇ %CPU:进程占用CPU资源的百分比。

◇ %MEM:进程使用内存RAM的百分比。

◇ VSZ, RSS:占用RAM的大小(Bytes)。

◇ TTY:表示进程执行者所登录的控制台或者终端。

◇ STAT:进程的状态,“R”为运行状态;“S”为睡眠状态,即中断执行,通常可以因事件发生而被唤醒;“T”表示进程正在侦测或者已停止;“D”表示在睡眠状态,除非发生指定事件,否则不会被唤醒;“Z”表示僵尸状态,例如未能被父进程回收的子进程,通常是一个系统bug或非法操作,需要以“kill”强制停止。

◇ START:进程开始的日期。

◇ TIME:进程用掉的CPU时间。

◇ COMMAND:所执行的命令(产生这个进程的命令)。

ps是一个相当有用的命令,经常被用来侦测系统的状态。其中最重要的信息是“PID”,因为kill等命令正是借助这个PID来管理和控制进程的。此外,为了了解当前系统中各个进程之间的父子关系,我们可以利用pstree命令来显示系统进程的树状结构。

(2)top。

ps是一个不错的进程检测工具,而使用top更可以用动态(每5秒刷新一次)的方式来检测进程的运行状态。

语法:# top

说明:在进入top环境后,可以输入以下的字符来改变结果的排序。

◇ A:以age即执行的先后顺序进行排序。

◇ T:以启动的时间排序。

◇ M:以占用内存的大小排序。

◇ P:以所耗用的CPU资源排序。

【范例】

# top
top - 04:02:46 up 8:22, 2 users, load average: 0.25, 0.08, 0.03
Tasks: 90 total,  2 running, 88 sleeping,  0 stopped,  0 zombie
Cpu(s): 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem:    255628k total,  212920k used,   42708k free,    5444k buffers
Swap:   1048568k total, 0k used,        1048568k free,  83384k cached
PID     USER    PR      NI      VIRT    RES     SHR     S       %CPU    %MEM  TIME+      COMMAND
1       root    15       0      2040    640     548     S        0.0     0.3     0:01.24 init
2       root    RT       0          0     0       0     S        0.0             0.0     0:00.00 migration/0
3       root    34      19          0     0       0     S        0.0             0.0     0:00.00 ksoftirqd/0
4       root    RT       0          0     0       0     S        0.0             0.0     0:00.00 watchdog/0
5       root    10      -5          0     0       0     S        0.0             0.0     0:00.05 events/0
6       root    10      -5          0     0       0     S        0.0             0.0     0:00.00 khelper
7       root    10      -5          0     0       0     S        0.0             0.0     0:00.00 kthread
10      root    10      -5          0     0       0     S        0.0             0.0     0:00.07 kblockd/0
……

(3)free。

语法:# free

说明:检查当前内存的使用情况。“-k”表示以KB为单位;“-m”表示以MB为单位。

【范例】

# free
                total           used            free    shared  buffers  cached
Mem:            255628          183100          72528   0       52320    81644
-/+ buffers/cache:              49136           206492
Swap:           1048568         0               1048568

上面的结果显示,目前有256MB 的物理内存,另有大约270MB的swap(虚拟内存)。

(4)控制进程的运行。

在Linux系统的运行过程中,有时会遇到某个进程由于异常情况,对系统停止了反应,此时就需要停止该进程的运行。另外,当发现一些不安全的异常进程时,也需要强行终止该进程的运行,为此,Linux提供了以下方式来结束进程的运行。

◇ Ctrl + c组合键:强制结束当前控制台运行的进程。

◇ kill命令:向指定PID的进程传送一个特定的信号,语法是:kill [-signal] PID。

◇ killall命令:杀死同一进程组内的所有进程。该命令允许指定要终止的进程的名称,而非PID,比如:killall named,就可以杀死和named服务相关的所有进程。

实际上,kill和killall除了用来结束指定的进程之外,还能对进程发出许多种控制信号,可以用“kill -l”列出所有可以由kill传递的信号。下面是几个主要的signal及其含义。

◇ 9:kill,强制终止,不论该进程是否处于僵尸状态。

◇ 15:terminal,正常停止,这是kill命令的默认信号值。

◇ 18:continue,继续执行。

◇ 19:stop,中断执行。

kill命令的语法是:# kill -signal PID。

说明:控制系统进程。此处signal用数字表示发出的控制信号;PID表示进程号。因此,要控制一个进程,首先需要运用ps、top等工具查出该进程的代号(PID)。另外,需要注意的是,由于很多进程都存在父子关系,只杀死某个子进程是无法将整个程序终止的。

【范例】

# ps –e | grep xinetd                                   // 查看指定的进程号
1665 ?  00:00:00 xinetd
# kill -9 1665                                                  // 正常结束编号为1665的xinetd进程

与kill命令的区别在于:killall命令使用进程名来控制指定的进程。若系统存在同名的多个进程,则这些进程将全部被管理,其用法为:

# killall -signal 进程名

例如,结束xinetd进程的运行,则实现命令为:

# killall xinetd

4.管理后台任务

默认情况下,一个前台进程在运行时将独占shell,并拒绝其他输入。反之,对每一个控制台,都允许多个后台进程。任务控制就是对前台和后台进程进行控制与调度。

所谓的木马就是常驻系统后台执行的小程序,主机上的信息就是由这些木马程序传送到入侵者手中的。因此,系统管理员必须养成良好的管理后台任务的习惯。此外,为了节省系统资源,Linux限制不能在前台执行多个任务。因此,我们有必要将一些任务放到后台执行,并运用一些技巧来管理和控制它们。下面我们来学习这些命令或者操作。

(1)[Ctrl]+z组合键。

说明:该组合键能将独占终端的前台进程调入后台并暂停执行。

【范例】

# vi /etc/hosts
^Z                                                  // 在vi的命令模式下输入[Ctrl]+z
[1]+  Stopped         vi /etc/hosts    // 显示已将任务放到后台

如果正在用vi编辑一个重要文件时,恰好暂时想离开,建议直接在vi的“命令模式”下使用[Ctrl]+z组合键,系统马上会将vi任务放到后台暂停其运行,并将此任务的编号、状态反馈给当前用户。此时前台会等待用户提交新的任务。如果想要继续执行vi任务,就需要使用bg或fg命令。

(2)jobs。

语法:# jobs

说明:显示后台的任务清单,包括具体的任务、任务号、任务当前的状态。

【范例】

# vi .bashrc
^Z                                                                    // 在vi的命令模式下输入“[Ctrl]+z”
[1]+  Stopped           vi .bashrc          // 显示已将任务放到后台
# jobs
[1]+  Stopped           vi .bashrc          // 显示后台有一个状态为中断的任务

上例使用jobs命令观察到当前后台的任务只有“vi .bashrc”这一项,中括号里面的数字就是该任务的编号。了解了这些情况后,我们才能对某个后台的任务进行管理。

(3)fg与bg。

语法:

# fg %number
# bg %number

说明:将任务挂起并可以在需要时从中止处恢复任务的运行。“bg”将挂起的任务放到后台继续执行,“fg”将挂起的任务调回到前台继续执行,它们都可以将任务的状态由“stopped”改变为“running”。%后面的数字表示任务号,默认操作最近挂起的任务。建议在执行这两个命令之前,首先使用jobs获取后台任务的编号。

【范例】

# find / -name test
^Z
[1]+  Stopped              find / -name testing   // 显示已将任务放到后台,编号为1
# vi .bashrc
^Z
[2]+  Stopped              vi .bashrc                             // 显示已将任务放到后台,编号为2
# jobs
[1]-  Stopped         find / -name testing
[2]+  Stopped         vi .bashrc
# bg %1                                                                         // 让1号任务在后台继续执行
# jobs
[1]-  Running         find / -name testing&      // 1号任务的状态变为“running”
[2]+  Stopped         vi .bashrc
# fg %2                                                                         // 把2号任务调回前台继续执行

(4)kill。

语法:# kill -signal %number

说明:控制后台任务。此处number表示任务号;signal的用法与管理进程的kill命令中的signal一样。

【范例】

# jobs
[1]+ Stopped    vi /etc/hosts
[2]- Stopped            vi .bashrc
# kill -9 %2