BBS水木清华站∶精华区

发信人: ruster (尘埃*星辰*领悟), 信区: Linux        
标  题: 第二章 Linux基础(下) 
发信站: BBS 水木清华站 (Thu Dec 21 13:27:31 2000) 
 
2.4 用户和权限 
   
  本节讨论Linux的用户/文件权限问题。许多用户不了解setuid和setgid,这使得他们 
在处理WWW server的cgi功能时出现种种问题。 
   
  2.4.1 用户、组和文件属性 
   
  Linux是一种多用户操作系统,为了确保在多用户环境下的系统运转的安全性,Linux 
使用用户权限机制对系统进行管理,这种管理主要是通过文件管理机制完成的。 
   
  Linux对每个文件设置一个16位数字来完成对文件的存取控制,这个数字称为文件属性 
。如同我们在前面说的那样,Linux并不使用文件名来区分文件的类型,文件的性质用文 
件属性来描述。在这个16位数字中有9位用于设置用户对文件的存取控制,3位用于对可 
执行文件进行特殊处理,另外3位用于设置文件的类型。这样说可能会让人有些迷糊,我 
们依次来处理这些问题。 
   
  文件类型在文件系统中我们已经提到过,它可以是设备文件,普通文件,目录,链接 
中的某一种,下面是一个信手拈来的例子: 
   
  ls -l 
   
  total 48 
   
  drwxr-xr-x   5 wanghy   wanghy       4096 Jan 21 13:25 Desktop 
   
  drwxrwxr-x   2 wanghy   wanghy       4096 Jan 28 14:25 bin 
   
  -rwxrwxrwx   1 wanghy   wanghy         10 Jan 27 19:43 cc 
   
  lrwxrwxrwx   1 root     root           19 Jan 27 10:33 ss -> /etc/X11/XF86 
Config 
   
  lrwxrwxrwx   1 root     root            2 Jan 27 10:29 test -> zz 
   
  -rwxrwxrwx   1 wanghy   wanghy         32 Jan 27 19:31 testpar 
   
  -rw-rw-r--   2 wanghy   wanghy          8 Jan 27 08:52 tk 
   
  -rw-rw-r--   2 wanghy   why          8 Jan 27 08:52 tt 
   
  -rw-rw-r--   1 root     root            8 Jan 27 10:29 zz      
   
  ls –l命令显示出文件的详细信息,它以分栏方式出现,最左面的一栏是文件属性栏 
。容易看到在文件属性中 
   
  drwxrwxr-x   2 wanghy   wanghy       4096 Jan 28 14:25 bin 
   
  最左面的d代表着这个文件是一个目录,它可以出现为一个l(软链接),b(块设备),c 
(字符设备),d(目录)或者简单地一个-号(普通文件)。 
   
  接下来的九个字母代表存取控制,从左至右每三个为一组,分成三组,分别代表文件 
的拥有者,同组用户和其他用户。 
   
  文件的拥有者是文件逻辑上的主人,只有他才能修改文件的属性。一般来说每当有人 
新建一个文件,他就自动地成为文件的拥有者。在第三栏我们看到的wangh就是文件系统 
纪录的文件拥有者。在拥有者权限栏位中出现的rwx表示拥有者可以直接读(r)、写(w)、 
执行(x)相应的文件。在这个形式 
   
  -rw-rw-r--   2 wanghy   why          8 Jan 27 08:52 tt 
   
  rw-表示文件的拥有者可以读和写这个文件,但是不能执行。一个-号代表相应的属性 
位没有被设置。 
   
  同组用户是在Linux用户管理中定义的该文件所属组的用户。所属组显示在ls –l输出 
的第四栏。所谓组就是在/etc/group文件中设置的一些集合,例如,下面的/etc/group 
文件 
   
  root:x:0:root 
   
  bin:x:1:root,bin,daemon 
   
  daemon:x:2:root,bin,daemon 
   
  sys:x:3:root,bin,adm 
   
  adm:x:4:root,adm,daemon     
   
  why:x:101:wanghy,adm,test 
   
  定义了root,bin,daemon,sys,adm和wanghy几个组。其中的why组包含wanghy,ad 
m和test三个用户。 
   
  刚才的tt文件在组权限这一栏的值是rw-,表示同组用户可以读和写这个文件,在这个 
例子中,就是why组,因此wanghy,adm和test都可以对这个文件进行读写。 
   
  最后,其他用户的权限是r--,意味着所有其它用户只能阅读这个文件,不能修改,也 
不能执行。 
   
  文件的拥有者可以用chmod命令更改文件的属性,也可以通过更改文件的属主把文件交 
给他人控制。 
   
  chmod命令的用法是 
   
  chmod 属性字 文件名 
   
  属性字有两种用法,最基本的用法是使用字母,用u,g,o分别代表文件拥有者,组用 
户和其他用户,+和-号用于调整权限。 
   
  例如,要给tt文件加上“拥有者可以执行”的权限,命令为 
   
  chmod u+x tt 
   
  取消tt的所有人可以读的属性的命令是 
   
  chmod o-s tt 
   
  chmod另外的一种用法是使用数字,为拥有者,组用户和其他用户分别计算一个数,计 
算规则是r=4,w=2,x=1,然后相加(例如,r-x=5),最后将三个数连到一起,例如为tt 
分配一个rwxrw-r—的属性的命令是 
   
  chmod 764 tt 
   
  文件的拥有者可以用chown命令将文件的所有权交给其他用户,但一旦交出就不能收回 
,例如,下面命令将tt的所有权交给root 
   
  chown root tt 
   
  有时需要对一个目录下的所有文件及下级子目录更改属性,这可以使用-R开关,例如 
: 
   
  chmod –R o+r share/* 
   
  一个有趣的问题是一个新创建的文件具有什么样的属性,这是通过umask命令实现的, 
设置了umask之后,你新创建的文件具有0777-umask的属性,例如,大部分系统的缺省u 
mask是002,因此用户新创建的文件属性就是777-002=775或者rwxrwxr-x。你总可以用自 
己的设置来改变这个umask值,例如 
   
  umask 066 
   
  将使得你以后的文件自动具有711属性。直接输入不带参数的umask命令则显示当前的 
umask。 
   
  2.4.2 超级用户和SU 
   
  UNIX的文件存取控制尽管十分有用,但是你系统在运行中总是会碰到需要绕过UNIX文 
件存取控制的情况。这是利用超级用户权限实现的。 
   
  UNIX的root用户大概是它最出名的地方,每个系统必须有一个root用户,这个用户执 
行系统的维护和管理。但是你要理解的是,对于系统来说这个名字其实没有意义。系统 
内核真正关心的是用户的uid。uid是一个整数,在/etc/passwd文件中定义,如果某个用 
户的uid等于零,系统将认为他是超级用户,从而对它不再使用存取限制和安全性验证。 
所以root用户可以操作任何人的文件或者象文件的拥有者一样管理文件。 
   
  root用户可以不受文件管理机制的影响,几乎可以做任何事情,由于unix的进程权限 
机制,root用户所执行的程序具有root权限,除非它自己将自己切换成为其他用户。 
   
  由于root用户可以访问整个文件系统,因此文件系统和用户组的管理都由它来完成。 
但是为了安全,许多实际的系统禁止root用户从服务器控制台以外的地方登陆,这意味 
着你不能直接从telnet以root身份进入系统。 
   
  即使能够用root身份远程进入系统,直接以一个uid=0的身份在系统上操作也是危险的 
,因为超级用户的误操作可以彻底破坏整个系统。一般的方式是以普通用户的身份进入 
系统,需要执行超级用户的任务时再用su命令切换成超级用户。 
   
  su命令本来是用来给普通用户切换成超级用户的,但是也可以用它切换成别的用户, 
其语法是 
   
  su 用户名 
   
  输入后,系统将提示你输入相应用户的口令,只有正确的口令才能完成身份切换。假 
如在su命令中没有给出用户名,那么系统缺省认为你要切换成超级用户,将提示你输入 
超级用户口令。 
   
  关于超级用户和用户管理的详细内容我们在用户管理一章中讨论。 
   
  刚才我们提到系统识别超级用户是通过uid,实际上整个UNIX的文件存取权限都是基于 
uid的,uid在/etc/passwd文件中定义,通常这个文件的属性是444,即全程可读,下面 
是一个例子: 
   
  [wanghy@openlab /etc]$ cat passwd 
   
  root:x:0:0:root:/root:/bin/bash 
   
  bin:x:1:1:bin:/bin: 
   
  daemon:x:2:2:daemon:/sbin: 
   
  adm:x:3:4:adm:/var/adm: 
   
  lp:x:4:7:lp:/var/spool/lpd: 
   
  sync:x:5:0:sync:/sbin:/bin/sync 
   
  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 
   
  halt:x:7:0:halt:/sbin:/sbin/halt 
   
  mail:x:8:12:mail:/var/spool/mail: 
   
  news:x:9:13:news:/var/spool/news: 
   
  uucp:x:10:14:uucp:/var/spool/uucp: 
   
  operator:x:11:0:operator:/root: 
   
  games:x:12:100:games:/usr/games: 
   
  gopher:x:13:30:gopher:/usr/lib/gopher-data: 
   
  ftp:x:14:50:FTP User:/ftp: 
   
  nobody:x:99:99:Nobody:/: 
   
  xfs:x:100:101:X Font Server:/etc/X11/fs:/bin/false 
   
  gdm:x:42:42::/home/gdm:/bin/bash 
   
  postgres:x:40:233:PostgreSQL Server:/var/lib/pgsql:/bin/bash 
   
  squid:x:23:23::/var/spool/squid:/dev/null 
   
  lyf:x:500:500::/home/lyf:/bin/bash 
   
  wanghy:x:501:501::/home/wanghy:/bin/bash 
   
  testvv:x:502:502::/home/testvv:/bin/bash      
   
  在每个用户名字后面有两个数字,前一个是uid,后一个是gid,gid用于标志用户属于 
哪个组。你可以看到root的uid和gid都是0。如果有一个用户的uid被设置成为0,那么他 
就自动地获得了root权限。 
   
  一个有趣的问题是passwd的属性,显然passwd必须确保至多仅对root可写,但是如果 
设置成400(仅超级用户可读)会如何呢?在大部分Linux上系统仍然能够工作,然而它会 
抱怨不知道哪个uid到底叫什么名字(“我不知道我叫什么名字“)。 
   
  除了超级用户之外,系统定义uid<10的用户为系统用户,而新建的用户将使用500以上 
的uid。 
   
  2.4.3 setuid和setgid 
   
  缺省情况下,Linux的用户保护机制不仅对于直接对文件的存取,也用于设置用户执行 
的程序,一个用户所启动的程序通常自动具有了这个用户的权限,也就是这个程序对文 
件的存取按照用户的权限执行。这使得用户不能绕过文件存取机制破坏文件系统。 
   
  然而很多情况下我们必须绕过文件保护机制,例如passwd程序,它用来更改用户的口 
令,在Linux的实现中它去修改/etc/passwd和/etc/shadow文件,因此它必须设计为以超 
级用户身份执行。为此,Linux提供setuid程序来完成这种工作。 
   
  setuid是一种文件特殊属性,它使得被设置了setuid位的程序无论被哪个用户启动, 
都自动具有文件拥有者的权限,可以看到passwd文件的属性是 
   
   [wanghy@openlab bin]$ ls -l passwd 
   
  -r-s--x--x   1 root     root        22312 Sep 25 11:52 passwd     
   
  文件属性中的s代表setuid,因为passwd程序的拥有者是root,因此passwd程序执行时 
自动获得超级用户权限,所以无论谁执行passwd程序都可以修改系统的口令文件。(说 
实话,这是UNIX的设计中的一个噩梦)另一个例子是web页面服务器,缺省时httpd服务 
器是利用nobody的权限执行,而且没有人愿意将自己的目录设置成777,因此httpd启动 
的程序无法修改用户的程序。对于需要写私人信息的cgi程序这显然是不可使用的,但是 
你可以为cgi程序加上setuid,这样你自己的cgi程序就可以修改自己的私有文件了。 
   
  setgid与setuid类似,只是具有setgid的可执行文件运行时自动获得文件对应的组权 
限,因为组权限不像用户权限那样精确,所以用setgid的程序不是很多。 
   
  setuid和setgid都是对正常的UNIX安全机制开的后门,原则上,只有在明确的非用不 
可的功能中才能使用setuid和setgid。特别是,具有root的setuid的应用程序经常是系 
统遭受攻击的目标。在安全性的部分我们将更详细地讨论setuid和setgid的问题。 
   
  要给一个文件加上setuid位,使用命令: 
   
  chmod u+s 文件名 
   
  同样,要加上setgid位,使用命令 
   
  chmod g+s 文件名 
   
  尽管理论上可以给不可执行的文件加上setuid和setgid,但是这样做通常没有什么意 
义。 
   
  2.5 进程和守护 
   
  进程概念是一切多任务操作系统的基础。本节介绍基本的进程管理命令。另外,还要 
介绍与服务器紧密相关的一大类进程,即守护进程。在术语中,守护进程称为daemon。 
   
  2.5.1 进程和作业管理 
   
  UNIX是一个多任务的操作系统,这是通过CPU在各个任务之间进行时间片轮转实现的, 
为此,UNIX/Linux通过进程的概念进行作业管理。 
   
  理论上,进程包括一个程序以及与它的执行状态对应的上下文,如内存分配,文件存 
取状态等等,不过你完全可以简单地把进程说成是“一个执行中的程序”。除了少数核 
心进程之外,其他的用户级进程就是这样一些东西。 
   
  一般把进程的状态分成下列几种: 
   
  运行态:进程随时可以执行 
   
  睡眠:由于进程缺少某些必要的资源,所以陷入了挂起的状态,只有得到某个信号才 
能继续运行 
   
  阻止:由于某个原因,系统向进程发出了一个阻止信号,于是进程暂时停止运行,直 
到接受到一个“继续运行”的信号才可以继续。 
   
  僵尸:进程本来应该已经死亡,但是由于某种原因,进程占用的id号还没有被释放。 
   
  为了显示系统中的所有进程,可以使用ps -aux命令,例如,下面是一个例子: 
   
  USER       PID %CPU %MEM   VSZ  RSS TTY      STAT START   TIME COMMAND 
   
  root         1  0.1  0.1  1104  368 ?        S    14:34   0:05 init [3] 
   
  root         2  0.1  0.0     0    0 ?        SW   14:34   0:05 [kflushd] 
   
  root         3  0.0  0.0     0    0 ?        SW   14:34   0:03 [kupdate] 
   
  root         4  0.0  0.0     0    0 ?        SW   14:34   0:00 [kpiod] 
   
  root         5  0.2  0.0     0    0 ?        SW   14:34   0:08 [kswapd] 
   
  bin        358  0.0  0.1  1196  288 ?        S    14:36   0:00 portmap 
   
  root       413  0.0  0.0  1156  180 ?        S    14:36   0:00 syslogd -m  

   
  root       424  0.0  0.0  1448    0 ?        SW   14:36   0:00 [klogd] 
   
  daemon     440  0.0  0.1  1128  296 ?        S    14:36   0:00 /usr/sbin/a 
td 
   
  root       456  0.0  0.0  1304  188 ?        S    14:36   0:00 crond 
   
  root       476  0.0  0.1  1124  436 ?        S    14:36   0:00 inetd 
   
  root       492  0.0  0.1  1176  436 ?        S    14:36   0:00 lpd 
   
  root       521  0.0  0.1  2104  284 ?        S    14:36   0:00 sendmail: a 
ccept$ 
   
  root       538  0.0  0.1  1144  384 ?        S    14:36   0:00 gpm -t ps/2 
   
  root       554  0.0  0.0  2560   68 ?        S    14:36   0:00 httpd       
   
  root       744  0.0  0.4  2216 1100 pts/0    S    14:59   0:00 login -wang 
hy$ 
   
  wanghy     745  0.0  0.3  1744  980 pts/0    S    14:59   0:00 -bash 
   
  root       815  3.2  0.4  1656 1088 tty1     S    15:26   0:26 ncftp 
   
  wanghy     827  0.0  0.3  2680  968 pts/0    R    15:40   0:00 ps -aux     
   
  root       845  0.0  0.3  1576  856 pts/0    T    15:48   0:00 vi 
   
  第一栏里给出的是进程的拥有者。不过这里有一些微妙的事情,进程有四个跟拥有者 
相关的数值,分别是uid,gid和euid、egid。后两者是进程执行时使用的“实际”身份, 
它们通常和uid与gid相同,然而对于一个setuid或者setgid程序,这里将显示进程的实 
际使用的权限。 
   
  第二栏的数值是进程的唯一pid号,或者进程标志符,操作系统用这个数字来标出进程 
的身份。 
   
  接下来的几行是一些信息,如CPU和内存的使用情况等等,第八栏是进程的执行状态, 
标有S说明这个进程正处于睡眠中,R表示进程处于运行中,而T表示进程被阻止,正在等 
待一个CONT信号让它重新投入运行。 
   
  在这里提到了信号这个词,信号大致就是系统向进程发出一个通知,警告它必须尽快 
去处理某些事情。在UNIX中定义了许多信号,但和普通用户及管理员关系最密切的有下 
面这样一些: 
   
  信号ID 名称 含义 是否可以捕获 是否可以阻塞?  
   
  1 SIGHUP 挂起 是 是  
   
  2 SIGINT 中断 是 是  
   
  3 SIGQUIT` 退出 是 是  
   
  9 SIGKILL 杀死进程 否 否  
   
  15 SIGTERM 软件终止 是 是  
   
  如果想了解关于信号的详细内容,可以参考linux头文件中的signal.h。实际上,对于 
最终用户,signal更多地用来杀死某个不应该被执行的进程,这是通过执行kill或者ki 
llall命令实现的。 
   
  kill命令用来向进程发送一个信号,其语法是 
   
  kill [-信号] 进程ID 
   
  其中的信号可以使用信号ID或者信号名,使用信号名时,前缀SIG省略,如果不明确地 
给出信号,那么使用信号SIGTERM。尽管技术上可以用kill向进程发送任何信号,但是实 
际上这个命令几乎总是用于杀死进程。进程ID就是在ps ax中看到的进程pid,例如,在 
上面的例子中,杀死portmap程序的命令是 
   
  kill 358 
   
  或者 
   
  kill –15 358 
   
  或者 
   
  kill –TERM 358 
   
  因为SIGTERM信号可以被捕获和阻塞,所以一个设计好的程序可以不理睬这个信号,如 
果要杀死这样的程序,可以使用SIGKILL信号,如: 
   
  kill –9 358 
   
  或者 
   
  kill –KILL 358 
   
  使用pid对许多人可能是不方便的,另外,可能有一个程序的多个拷贝在内存中执行, 
一个一个地杀死这些程序有时是很讨厌的事情,为此,Linux提供了killall命令。kill 
all和kill基本等同,但是它使用进程名而不是pid来发送信号,因此可以一次杀死所有 
同名进程。 
   
  kill –l或者killall –l将显示所有可用的信号。 
   
  有一个信号SIGTSTP用于定义“键盘阻止”。处于某些原因,你可能想暂停当前的某个 
工作而去进行某个更重要的工作,这可以通过按下^Z来完成,按下这个组合键时,系统 
象当前的前台程序发送SIGTSTP信号,于是当前程序被阻止,你可以在这个期间进行其他 
工作,例如,在前面的例子中显示的被阻止的vi就是这样一个程序,用jobs命令可以显 
示当前被^Z挂起的程序: 
   
  [openlab]# jobs 
   
  [1]+  Stopped                 vi   
   
  最前面的号码是作业号,在挂起这个程序之后,你可以用fg命令将它重新投入前台运 
行,或者用bg命令将它放到后台去执行。 
   
  语法是 
   
  fg [作业号] 
   
  bg [作业号] 
   
  省略作业号则执行最近被阻止的作业。 
   
   当一个进程的父进程被撤销时,它通常会接受到撤销信号,从而它也会退出。 
   
   另外一个常用的指令是&,它通常用于避免程序截获前台输入,例如,在xterm下,直 
接执行netscape & 将启动netscape 程序,在netscape退出前,xterm只能等待。相反, 
netscape &指令启动netscape,同时xterm仍然可以处理前台命令。 
   
  2.5.2 forks和exec 
   
  forks是UNIX中被程序员熟知的功能之一。简单地讲,forks创造一个新的进程。 
   
  实际上,forks是一个进程用来克隆自身的方法,某个进程调用forks将在内存中开设 
一个自身的拷贝,即建立一个与自身几乎完全相同的进程。执行forks的进程称为父进程 
,而克隆出的进程称为子进程。两者只有非常小的区别:两个进程的pid号不同;新进程 
要建立自己的一些资源。 
   
  实际上,整个UNIX的进程创建机制都是基于forks的。执行一个新的程序在UNIX中有一 
个专门的功能组,称为exec,它包含彼此差不多的一些函数族,如execl,execv等等,功 
能上也相似,都是去执行另外一个程序。但是,UNIX的exec函数被设计为被执行的程序 
接管原来程序的全部资源,因此当被执行的程序结束以后,执行程序也就消亡了。显然 
,这不是我们想要的,所以,UNIX/Linux在准备启动一个新的程序时,负责启动的程序 
首先调用forks产生出一个新的进程,在这个过程中它使用forks的一个功能,即forks函 
数自动区分是原始进程还是被forks出来的进程,如果是子进程则调用exec来执行所要调 
用的程序。 
   
  一个主进程可以forks出多个子进程,当然,forks越多,就消耗越多的资源,有时这 
可能是很讨厌的,因此,在大部分Linux系统上限制每个进程只能forks出有限的进程数 
,缺省下这个数字是256。因为许多服务器守护进程都依赖于forks,所以这个限制经常 
是服务器噩梦的来源。如果你的网络负担非常沉重,你可能必须手工调节这个数字把它 
加大到一个合理的值。(不过,也许使用更强大的系统是更合适的解决方法?) 
   
  要察看当前的 forks极限,使用ulimit命令: 
   
  [wanghy@openlab wanghy]$ ulimit -u 
   
  256                               
   
  如果要设置forks极限,使用带参数的ulimit指令: 
   
  ulimit –u 512 
   
  这个命令将forks极限设置为512。 
   
  ulimit –u unlimited 
   
  这个命令取消对forks的限制。 
   
  另一个问题是进程的优先级。内核调度任务时,优先级越高的任务能得到越高的CPU使 
用率。一般情况下,内核会自动安排进程的优先级,而且这种普通的进程优先级机制已 
经完全够用,然而,在某些极端的情况下,你可能想让某些任务以尽可能高的优先级执 
行。 
   
  强行指定某个进程的优先级是不可能的,但是你可以在一定的范围内让某个任务以尽 
可能高的优先级运行,这可以用nice命令实现: 
   
  nice –n -15 sh 
   
  这个命令让你以一个很高的优先级执行一个新的shell。-n后面的数用来标志你对这个 
进程的期待值,这个数越小,进程的优先级越高,范围是从-20到19。 
   
  启动的进程仍然可以用renice命令修改期待值,例如: 
   
  renice –20 1553 
   
  将pid为1553的程序的优先级提升到最高。 
   
  2.5.3 守护和服务器守护程序 
   
  守护程序就是一个在后台跑的程序,它通常用来执行一些系统相关的任务。大部分守护 
进程都是在系统启动是投入运行,随时等待呼叫。但是守护程序也可以设置为手动启动 
和停止。 
   
   最基本的守护程序是init程序,当系统启动后它就开始运行,实际上除了内核产生的 
进程以外所有的进程都是init直接间接地forks出来的。另外两个几乎一切UNIX都必须提 
供的守护程序是inetd和crond,crond用来设置在某个特定的时间执行特定的工作(例如 
:在每星期六晚上10:00开始整理硬盘)。 
   
   inetd是一个用来管理许多存取不太频繁的服务进程的守护程序,它在有任务时启动 
对应的服务进程并且在网络客户程序和服务进程之间执行翻译,通过inetd启动的服务器 
进程可以不理会复杂的BSD网络编程接口,inetd把通过网络的通信翻译成普通的文件读 
写操作,使得编程变得简单,但是相应地,inetd的效能不是很好,因此重负荷的应用通 
常用独立的守护进程实现。 
   
   大部分独立的网络服务被实现为服务器守护程序,它们可以被绑定在某一个端口上, 
在后台接受客户的请求,许多这样的守护程序使用forks机制来完成工作,例如sendmai 
l。sendmail监听向25端口的请求,当接受到一个这样的请求时,它forks出一个自身的 
拷贝,将连结请求交给这个子进程,然后它自己又可以在25端口上继续监听。 
   
   由于forks的问题,个别服务器守护程序会在内存中产生多个子进程,例如httpd程序 
,在一台负担很重的机器上,它可以产生出几百个子进程,而只有第一个进程是真正的 
控制进程。要找到这样的进程当然可以用more和grep命令仔细寻找,但是Linux系统中提 
供别的方法,前面讲到的killall是一个可行的方案,另外一个方法包含在/var/run目录 
中,其中会以xxxx.pid的形式包含了守护进程启动时(第一个)的pid,其命名方法就是 
守护进程的名字(如果是在inetd.conf中启动的守护进程则由inetd程序命名),格式就 
是一个简单的文本文件,例如: 
   
  [wanghy@mail run]$ cat /var/run/httpd.pid 
   
  392 
   
  [wanghy@mail run]$ ps ax | grep httpd | more 
   
    392 ?        S      0:00 httpd 
   
  26070 ?        S      0:00 httpd 
   
  26071 ?        S      0:00 httpd 
   
  26072 ?        S      0:00 httpd 
   
  26073 ?        S      0:00 httpd 
   
  26074 ?        S      0:00 httpd 
   
  显然杀死httpd进程的命令是 
   
  kill `cat httpd.pid` 
   
  注意反引号是执行其中的命令。 
   
  但是要注意sendmail有所不同,其pid文件除了包含pid号之外,还包含了sendmail的 
启动命令: 
   
  [wanghy@mail run]$ cat sendmail.pid 
   
  363 
   
  /usr/sbin/sendmail -bd -q1 
   
   下面是常用的网络服务器守护进程的列表: 
   
   inetd:启动其他网络服务的服务器 
   
    下面是由inetd启动的常用服务器: 
   
  sendmail:邮件传输服务器 
   
   in.telnetd:telnet服务程序 
   
    in.ftpd:ftp服务器 
   
  pop3d:邮局协议服务器,用于向邮件客户机器最终传送邮件和管理服务器上存储的邮 
件。 
   
   下面是一些其他的服务器: 
   
   httpd:Apache WWW服务器的守护程序 
   
   smbd:windows 9x类型文件服务程序 
   
   nfsd:网络文件系统服务器 
   
  portmap:端口映射服务,为很多其他服务器提供服务 
   
  lpd:打印机服务程序 
   
  named:网络域名服务器 
   
  nmbd:广播netbios名字的服务程序 
   
  innd:电子新闻组服务器 
   
  routed:路由服务器 
   
  sshd:SSL shell服务程序 
   
  守护程序对信号的响应与一般进程稍有不同,例如,SIGHUP信号通常将使接受到这个 
信号的程序终止。但是当一个守护程序接受到这个信号时,它简单地让自己重新启动。 
实际上,在调试服务器时经常需要重新启动守护进程,而killall –HUP是简单可靠地重 
启某个服务器守护进程的标准方式。 
   
  另一个容易出现问题的地方是守护程序的uid。如同我们在第一张中解释的那样,为了 
进行服务,守护程序必须将自己绑定(bind)到某个端口。TCP/IP实现中保留小于1024 
的端口号用于提供服务,而更高的端口可以用于客户程序发起请求。考虑到这种情况, 
UNIX要求凡是绑定到数值小于1024的端口的程序必须具有root权限,这意味着大部分服 
务器守护进程必须以root身份执行,因此它们可以做任何事情,这潜在地对系统的安全 
性构成了威胁(显然,你不能从普通用户的身份启动httpd)。幸运的是,大部分服务器 
守护程序在设计的时候都已经考虑了这个问题,有些程序让inetd来完成绑定,因此它们 
可以以一个比较低的权限来执行,而另外一些程序则用一个具有root权限的进程处理所 
有的请求,当得到一个请求时,它forks出一个子进程,并且将子进程的euid设成权限比 
较低的用户,然后再让子进程处理这个请求。例如,apache服务器当使用独立程序启动 
时就使用类似这样的方式。也有一些守护进程必须以root身份执行,最典型的是sendma 
il,对于这样的程序必须小心,因为许多攻击都是利用这种程序的漏洞。 
   
  2.6 账户管理 
   
  在你安装系统之后,你必须建立一些用户以便使用。尽管技术上建立和删除账户应该 
在日常管理的部分完成,但是我们这本书是一本教程,如果等到讲日常管理那一章再出 
理,你的Linux可能已经被错误操作破坏了n次了。 
   
   2.6.1  口令文件 
   
  Linux是一个多用户操作系统,在系统中可以有多个用户在同时工作,为了管理账户, 
Linux使用两个文件,称为/etc/passwd和/etc/shadow。 
   
  passwd文件在前面就已经提到过,现在来详细的解释一下,让我们看一看前面提到的 
/etc/passwd文件,通常这个文件每行代表一个用户,格式是这样: 
   
  wanghy: $1$EtinNb.u$uMi3KAS9l9XY1CNJ99zWB1:501:501::/home/wanghy:/bin/bash 
   
  各个栏目之间用冒号分开,第一栏是用户的名字,就是在系统的login:提示符下输入 
的名字,接下来的一栏是加密后存放的口令字,在一般的UNIX系统上,这个加密使用DE 
S加密算法,但是由于计算机技术的发展,短密钥的DES加密技术已经无法提供足够的安 
全性,而长密钥加密系统要受到美国法律的限制。目前,Linux支持MD5加密方式,这种 
加密方式产生的密文就类似于上面的情况。当然,你仍然可以使用原来的DES短密钥方式 
,但其可靠性不是很高。 
   
  下面的两栏是uid和gid,UNIX通过这两个值来确定用户身份。然后有一栏是空的,这 
一栏曾经用来填写用户的详细资料,不过UNIX从不使用这个内容,因此你可以让它空着 
。 
   
  /home/wanghy是这个用户的宿主目录,注意这个目录必须是这个用户可以访问的,否 
则无法登录,接下来,/bin/bash是用户登录时使用的缺省shell。 
   
  上面说的是passwd的原始形式,不过,这种形式中口令密文被存放在passwd中,意味 
着任何人都可以看到。尽管MD5的加密强度比较高,但是利用高性能的计算机和蛮力搜索 
的方法,完全有可能用穷举的方式找出用户的口令原文(办法就是猜测一个口令,加密 
演算后和密文比较,如此循环)。特别是UNIX的口令通常限制为不多于8个字符,一个有 
足够决心的口令猜测者是有可能完成的。因此,几乎所有的Linux系统都使用shadow方式 
,这种方式中,密文保存在shadow文件中,而passwd文件中只有一个"x",例如,在/et 
c/passwd中: 
   
  wanghy:x:501:501::/home/wanghy:/bin/bash 
   
  而同时系统中有一00个shadow文件,它才是真实的password文件,但是它被设置为只 
有超级用户才能读取,下面是/etc/shadow文件中的相应内容: 
   
  wanghy:$1$EtinNb.u$uMi3KAS9l9XY1CNJ99zWB1:10977:0:99999:7:-1:-1:134550524 
   
  在口令密文之后的几项是一些设置,例如口令被更改的时间,口令的有效期等等。不 
过你实在没有理由一定要研究它们,useradd和adduser程序会做同样的事情。 
   
  传统上,可以使用直接编辑passwd文件的方式来管理用户信息,这种方式最常用的是 
用来建立一个没有口令的用户。但是如上所述,要使得更改有效,必须同时修改passwd 
和shadow文件才能完成这个工作,为了解决这个问题,可以使用pwconv程序,它可以根 
据/etc/passwd的内容对/etc/shadow文件进行同步。 
 
   
  $ pwconv 
   
  通过passwd中的口令栏的设定(实际是/etc/shadow文件的设定),可以设置不需要口 
令就可以登录的用户和禁止登录的用户,例如,这样的passwd设定: 
   
  testvv:*:502:502::/home/testvv:/bin/bash 
   
  口令处的星号将testvv设置为无法登录,相反,如果这里是空的,表示不需要口令: 
   
  testvv::502:502::/home/testvv:/bin/bash 
   
  另一对用来做账户管理的文件是/etc/group和/etc/gshadow。这两个文件用来管理用 
户组,其关系相当于passwd和shadow,例如,下面的group文件: 
   
  root:x:0:root 
   
  bin:x:1:root,bin,daemon 
   
  daemon:x:2:root,bin,daemon 
   
  sys:x:3:root,bin,adm 
   
  adm:x:4:root,adm,daemon 
   
  定义了五个用户组,每行一个,如bin的用户组gid是1,其中包括root,bin和daemon三 
个用户。对应的口令文件在/etc/gshadow,同样可以手工编辑/etc/group文件进行用户 
组的管理,然后用grpconv来同步: 
   
  $ grpconv 
 
   
  2.6.2   账户的添加和删除 
   
  显然,我们可以手工修改/etc/passwd文件来实现账户的添加和删除,不过除非你右受 
虐倾向,否则意义不大(如果你真的要这么干,你可以使用vipw程序)。相反,我们建 
议使用adduser程序。 
   
  adduser程序最简单的用法是 
   
  adduser [用户名] 
   
  例如,adduser test将建立一个名为test的用户。 
   
  adduse有一些常用的命令开关: 
   
  -c [注释] 填写passwd文件中的注释域的内容(就是那个从来不用的栏目) 
   
  -d [宿主目录] 定义用户的宿主目录,这个目录将被自动创建,如果缺省,使用/hom 
e/用户名,例如,对于test用户就是/home/test 
   
  -e [有效期] 到哪一天用户的这个账号口令将被失效,格式是YYYY-MM-DD 
   
  -f [天数] 口令达到有效期的话对用户警告的天数,超过这个天数账号就会被禁止登 
录。缺省值是-1,表示永远不会真正禁止登录。 
   
  -G [组名]  用户属于哪个组 
   
  -m 创建宿主目录,这是缺省值 
   
  -M 不创建宿主目录 
   
  -n 建立用户的同时建立一个同名的用户组,这个是缺省值 
   
  -s [路径名] 用户的登录shell 
   
  -u [uid]  用户的uid 
   
  在建立用户时,缺省的情况下,一些基本的设置定义在/etc/login.defs文件中,而如 
果存在/etc/skel目录的话,这个目录中的所有文件都会被拷贝到用户的宿主目录中,所 
以你可以设计一套比较好的配置文件,如.bashrc,.profile等等,然后放在/etc/skel 
目录中。 
   
  刚刚建立的Linux帐户是帐户是无法登录的,为了使用户能够以这个用户名登录,超级 
用户必须执行passwd程序为用户设置口令,例如,建立了test用户之后: 
   
   passwd test 
   
  系统将提示你输入用户口令并且确认,确认之后就可以使用这个帐户了。 
   
  要删除某个帐户,使用userdel命令: 
   
  userdel [-r] [用户名] 
   
  -r选项在删除用户的同时也会自动删除他的宿主目录。 
   
  2.6.2   特殊账户 
   
  在一般的系统中,都会有一些特殊的账户,许多这些账户都是系统进行管理或者执行 
服务功能用的,这些账户被设置为不可登录(在shadow文件中的口令域是一个*)。例如 
daemon,uucp,lp,mail,news等等。 
   
  有一个账户是特别需要注意的,即nobody用户,它相当于其他系统的guest账号,缺省 
下的这个账户是 
   
  nobody:x:99:99:Nobody:/: 
   
  由于是一个guest账户,所以不应该有任何文件属于它,以免引起安全性问题。在许多 
系统上,nobody的uid是65535(-1),不过为了避免出现稀疏文件问题,Linux用一个小得 
多的数值。 
 
   
  2.7 Linux版本和其他服务器系统 
   
  现在我们介绍一些关于Linux的知识。这些东西仅仅是一些个人看法,信不信是你自己 
的事情。 
   
  2.7.1 Linux的内核版本和发行版本 
   
  关于Linux的版本问题有两种主要的内容,分别是内核版本和发行版本。内核版本就是 
我们前面提到的,由Linus维护的系统内核的版本,由于每天都有新的要求提出或是新的 
漏洞被发现,因此从产生的那一天起Linux内核就在不断的修改和升级之中。一般情况下 
,对于一个服务器系统,我们关心的是那些已经被发布的稳定版本,目前这个系列的主 
要版本号是2.2,我用的是2.2.14,另外,2.4的版本也即将发布。 
   
  一般来说,关心内核版本号的主要理由是编译应用程序或者修补已知的漏洞。对于编 
译应用程序,可以认为主版本号相同的系统之间的差异可以忽略,而如果主版本号不同 
就可能为你的移植过程带来烦恼。另外,由于新的漏洞不断地被发现,所以不断地升级 
你的内核可能是必要的,至少,了解自己使用的内核是十分重要的。 
   
  另一方面,我们能接触到的通常都是发行版本,发行版本其实就是某个厂商或者组织 
搜集了一些应用程序,编译并且打包,然后以CD-ROM的方式发布出来。对于应用软件来 
说,各种发行版本之间的差别实际是很小的,但是,对于系统管理员的日常维护,它们 
之间的关系就很讨厌了。 
   
  各种发行版本通常都有自己的安装程序,为了安装程序的方便,各个版本按照自己的 
方案对系统的目录(主要是/etc)往往要进行重新组织,结果是,一个熟悉redhat的配 
置专家可能在debian面前晕头转向。 
   
  大量使用的配置程序往往使问题变得更加复杂。基于菜单或者图形的配置工具通常会 
使得问题变得简单一些,但是它们往往依赖于假定某些文件“就在某个地方”,结果当 
你试图把它们移植到别的发行版本的时候,你会发现过大的工作量会使你感到根本不值 
得。 
   
  另外,每种发行版本都会带有自己搜集的一些应用程序,技术上说这些程序不是发行 
版本的一部分,你可以从别的地方拿到这些程序,或者把某个发行版本里的程序拿到其 
他发行版本里面用。 
   
   值得说明的是,目前有所谓“中文的Linux”,笔者无意对此多加评述,但是对于一 
个服务器来说,中文界面实际是不需要的。由于Linux内核的原因,无论中文或者英文的 
Linux服务器都可以建立和管理中文的文件名。既然你不会用一台服务器作为上网的浏览 
工具,那么中文化对你并无现实的好处,而在目前,许多中文化系统都必须在系统内核 
或者别的什么地方打上一些补丁,它们潜在地引入了不稳定因素。 
   
  目前发行的Linux主要版本中,有些是为桌面准备的,例如corel的产品,也有一些由 
于某种原因很难拿到。在剩下的产品中,我建议你考虑如下产品: 
   
  redhat :如果你是一个新手,你可以考虑这个产品。它包含大量的配置命令和附加程 
序,非常容易安装和配置。 
   
  Slackware:这是一个适合于喜欢手工编写系统配置程序但是经验不是很多的用户的版 
本,它的脚本组织的很简单也很清晰。不幸的是它包含的附加程序比较少,你可能不得 
不从网络上下载大量的东西以便使用 
   
  Turbo Linux Chinese:这是一个中文化的版本,谢天谢地它的中文是用外挂应用程序 
的方式实现的,也就是如果你不使用中文你就可以把中文补丁拆掉。其完整发行版本包 
含10张CD-ROM,包含了一般情况下你需要的“几乎所有”的东西,价格也不菲(300元以 
上,当然相对于其价值来说便宜得难以想象)。尽管如此,它的某些为了中文化而做的 
努力对于服务器管理者可能还是十分讨厌的。 
   
  红旗Linux:这个可以合情合理地看成redhat的汉化版本,不过好像没有源代码包,其 
他关于redhat的评语都可以直接用到它上面。价格么。。。。比redhat贵一些。 
   
  2.7.2  其他服务器操作系统 
   
  选择Linux作为网络服务器的主要理由是性能价格比。任何Linux发行版本的价格相对 
于网络服务器或者管理费用都是可以忽略的,除此之外,另外的一些原因也在考虑之列 
,比如管理的复杂性,维护和技术支持的费用等等,未来的可升级性。 
   
  通常你不会是网络工程的负责者而仅仅是一个服务器或者网络系统的管理员,因此这 
里列出一些常见的网络服务器操作系统,将它们和Linux做一些对比,也许这些比较能说 
明你的老板选择Linux,也许不能。 
   
  在谈论这些比较之前我们应该首先澄清几个问题。许多传统UNIX的用户宣称Linux是“ 
一个玩具”,笔者并不反对这个说法,但是任何系统都是从玩具发展起来的。在当年IB 
M vs UNIX,UNIX vs Windows NT和CP/M vs MS-DOS我们都听到过前者对后者的贬低。对 
这个问题的最佳回答是,如果市场上的10元人民币的玩具小汽车能够带20吨有效载荷以 
每小时200公里的速度从北京跑到哈尔滨,而一百万元的名牌载重卡车却只能每小时跑5 
0公里,那么没有人在乎他们用的是不是玩具汽车。另外一个典型的误解是,软件价格总 
是可以忽略的。事实上,当你面对那些商业产品的时候,这个概念可能正确也可能不正 
确,例如,Solaris只需要很低的费用就可以买到,然而你也许必须购买昂贵的专用工作 
站来跑它,总的成本可能远远超出你的想象。 
   
  另一个很重要的问题是,Linux是一种低端产品,显然,用18元的redhat加上一万元的 
DIY机器与上百万元的IBM大型机相互比较是毫无意义的,我们的讨论将限于在低端使用 
的那些常用的服务器系统。这主要包括Solaris,SCO UNIX,Windows NT和FreeBSD,由 
于使用Netware的用户已经很少,所以我们将不再讨论这个产品了。 
   
  所谓低端,我们是在x86服务器的意义上说的,它通常指这样的一个系统: 
   
  处理速度低于每秒10亿次(比如说双Pentium III 500或者G4之类的处理器) 
   
  内存不多于512MB(在x86系统上通常可以配置很多的内存,相反,工作站系统的内存 
经常会让人无法接受。尽管工作站内存比普通的DRAM效果好,但是在繁重的任务中,内 
存耗尽通常是首先发生的,存储器的容量比质量更重要) 
   
  网络接口的速度不高于100M(GB级的以太网已经开始使用,然而,一个GB级的网络服 
务器意味着什么样的服务器负担?) 
   
  同时连接数低于1000(这是一个什么概念?它意味着你的网站将接受每天上百万甚至 
几百万的访问量) 
   
  ①Linux & Windows NT 
   
  这两者都运行在x86系统上,而且技术上说你绝对可以用DIY的机器运行Windows NT, 
但是两者仍然有区别。 
   
  Windows NT一直被Linux用户诟病的是它的执行效率,以及易于崩溃的名声。与某些宣 
传相反,实际上Windows NT对硬件的要求是极其奢侈的。实际上我怀疑能否在我们这里 
说的“低端”硬件上有效地运行Windows NT。在双PIII Xeon+512MB内存的系统上Windo 
ws NT表现的还可以,但是在PII 350+64MB的系统上Windows NT表现的如同蜗牛一般,而 
且应该记住Microsoft的“官方”说法是NT的系统要求是Pentium 166+32MB。在那些典型 
的Linux vs NT的测试中,使用的内存通常高达2GB,我怀疑你是否有足够的预算来完成 
一个基于NT的系统。下面是一些来自Microsoft的关于Windows 2000 Server的信息,你 
可以自己对你需要的硬件进行一个估计: 
   
     
   
  Windows 2000 Server硬件要求 
   
     
   
  133MHz或更高的Pentium兼容的CPU  
   
  建议至少有256MB的RAM(最小支持128MB;最大支持4GB )  
   
  2GB的硬盘,至少有1.0GB的空闲空间(如果你是通过网络进行安装将需要额外的硬盘 
空间)  
   
  Windows 2000 Server最多支持在一台机器上有4个CPU  
 
   
    除此之外,Microsoft Exchange Server又是一个额外的预算开销。你可以不使用N 
T的文件和打印服务而仅仅让它作为Web服务,这样不涉及许可证问题,但是你不可能不 
让你的用户使用电子邮件,而Exchange Server的许可证费用足以让你破产。另外,就我 
们所知道的,Exchange Server至少需要128MB内存和双CPU才能以合理的速度运转。(当 
然,是在Microsoft的意义上的“合理速度!”) 
   
  相反,Linux的硬件需求低的多,事实上,一台普通的PII +64MB内存可能就足以满足 
一个普通的公司的需求。而且你不需要考虑烦人的许可证限制。特别是,由于Linux的投 
资如此之小,所以在任何情况下,你都可以首先试验一下,即使不成功你也决不会损失 
什么。 
   
  ②Linux & 商业UNIX 
   
  无疑很多人仍然愿意选择商业的UNIX。由于商业的UNIX多数运行在RISC系统上,把它 
们和DIY的x86兼容机相比显然毫无意义。但是也有一些可以在x86系统上运行的UNIX实现 
,如Solaris for X86和SCO UNIX。 
   
  Solaris for x86是一个典型的产品,其SPARC版本已经为人们所熟知,但是x86版本并 
没有经受过太多的考验。尽管Sun的支持者大量宣传Linux如何不稳定,或者如何缺少复 
杂的特性,但是在x86上Solaris并没有表现出比Linux更高的稳定性(Solaris的图形倒确 
实比Linux好得多,但是这肯定不是一个服务器管理员所关心的),而且,尽管理论上So 
laris是一种出色的产品,但是一个甚至不包含编译器的UNIX系统是你需要的吗? 
   
  Solaris确实拥有许多应用程序,但是在普通的Solaris发行版本中并不包含这些东西 
,你得另外购买,而且,Sun提供的许多程序并不是世界上大部分人正在使用的那一种, 
你可能必须完成Sun的专门培训才能成功地使用这个产品,这意味着额外的开销。当然, 
你可以去寻找免费的程序并且编译它们,但是这就会面对一个新的问题,Solaris的普通 
发行版不包含编译器,所以你或者出一笔额外的开支购买C编译器,或者去下载GNU的GC 
C编译器,但是后者在Solaris系统中到底会产生什么样的代码很难说。这是因为Solari 
s并不是一种标准的UNIX,(或者说,既不是SYSTEM V也不是BSD),而且Sun出于自己的 
目的更改了许多东西,你会发现这是一件非常头痛的事情。 
   
  当然SPARC上的Solaris具有比Linux更好的稳定性和带负载能力,但是我想在现在x86 
芯片以18个月加快一倍的速度发展的时代,你肯定不愿意每年购买一台SPARC然后在年底 
将它淘汰(也许你可以不淘汰,但是你愿意相信200MHZ的SPARC在性能上能超越600MHZ  
Pentium III Xeon吗?),相反,每年淘汰几台x86倒是任何公司都会干的事情。 
   
  [有一个真实的例子。我们曾经购买了一台SPARC工作站用来作为Internet服务器,但 
是某一天它的sendmail配置坏了,于是我们需要重新配置,但是没有人能从头写一个se 
ndmail.cf,所以我们试图使用m4程序来完成,但是发现在那个版本的solaris中不包含 
配置sendmail必要的一些文件,而且对于当时14.4KB的连接速度,下载sendmail配置程 
序显然是不现实的。于是这台SPARC就变成了废物,所有人无奈地等待他们的电子邮件, 
直到最后我们用一台Linux代替了它。现在我们用那台Solaris当成执行Linux图形程序的 
终端。] 
   
  SCO UNIX是另外一个例子,它通常用于银行和保险业中,由于历史上的原因,SCO的局 
域网支持是不错的的,但是其Internet服务器程序不是很好。而且SCO UNIX大概是最古 
怪的UNIX实现之一,无论如何,我们不会建议一个新手使用SCO。 
   
  ③Linux & BSD 
   
  对于低端的应用,也许唯一可以对Linux构成威胁的是BSD家族的成员,特别是FreeBS 
D。 
   
  FreeBSD也是一个免费的UNIX系统,不同的是它是一个纯的UNIX系统,是一个标准的B 
SD风格UNIX的实现,另外,它的版权规则和GPL不同。由于原始设计的一些原因,FreeB 
SD的网络特性要比Linux好一些,特别在系统负担沉重的时候。许多著名的网站都是利用 
它构成的。 
   
  本书作者同时使用Linux和FreeBSD,但是在单位的网站上则使用Linux。事实上,Fre 
eBSD超强的带负载能力显然对于象作者所面对的那样的环境是没有必要的,而Linux相对 
于FreeBSD则表现了容易管理和支持硬件较多的优点。另外,由于要作为Proxy Server, 
所以Linux的高速缓存文件的能力是非常重要的,相反,FreeBSD的磁盘处理速度不是很 
令人满意。 
   
  尽管如此,作者同样相当欣赏FreeBSD,事实上,如果你要做的是一个极其庞大负担也 
十分繁重的系统,那么,可能FreeBSD会是比较好的选择,相反,如果你的主要任务是文 
件和打印服务,或是如同我们一样用DDN专线连入Internet,那么Linux可能更合适一些 
。  
 
 
-- 
当我越过无尽虚空的时候,我看见星辰的欲望,光荣和毁灭,这是光辉世界的宿命, 
一切的一切,最终必将落入黑暗和虚无。 
所以,我随着星光飞翔,去逃脱必然的终结,也许有一天,我将回到世界的原初, 
等待新的星辰的诞生。 
尘埃是星的起源,星的终结。 
 
 
※ 来源:·BBS 水木清华站 smth.org·[FROM: 202.112.90.20] 

BBS水木清华站∶精华区