Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1744258
  • 博文数量: 438
  • 博客积分: 9799
  • 博客等级: 中将
  • 技术积分: 6092
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-25 17:25
文章分类

全部博文(438)

文章存档

2019年(1)

2013年(8)

2012年(429)

分类: 系统运维

2012-03-30 17:37:28

让我们从当我们登录UNIX系统执行的程序开始。在早期UNIX系统,比如版本7,用户使用用硬线连接到主机的哑终端登录。这个终端或是本地的(直 接连接的)或远程的(通过猫连接)。在任一情况下,这些登录经过内核里的终端设备驱动。例如,在PDP-11上的通用设备是DH-11和DZ-11.一个 主机有固定数量的这些终端设备,所以在同时登录数量上有一个已知的上限。


当位映射图形化终端变得可用时,窗口系统被开发出来以提供用户与主机计算机交互的新方式。应用程序被开发出来创建“终端窗口”来模拟基于字符的终端,以允许用户用熟悉的方式与主机交互(也就是说,通过外壳的命令行。)


今天,一些平台允许你在登录后开启一个窗口系统,而其它平台自动为你启动窗口系统。在后面一种情况里,你可能仍然必须登录,取决于窗口系统如何被配置(一些窗口系统可以被配置为为你自动登录。)


我们现在描述的过程被用来使用一个终端登录一个UNIX系统。这个过程是相似的,而不管我们系统的终端类型--它可以是一个基于字符的终端,一个模拟一个简单基于字符的终端的图形化终端,或者运行一个窗口系统的一个图形化终端。


BSD 终端登录


这 个过程在过去30多年没有改变很多。系统管理员创建一个文件,通常是/etc/ttys,每个终端设备有一行。每行指定设备名和传入getty程序的其它 参数。例如一个参数是终端的波特率。当系统被引导启动时,内核创建了进程ID

1,init进程,而就是init引入系统多用户。init进程读取/etc/ttys文件,并为每个允许一个登录的终端设备执行一个fork,再执行一 个程序getty的exec。


对于每个终端fork出的运行getty的子进程,都有一个值为0的真实用户ID和值为0的有效用户ID(也就是说,它们都有超级用户权限)。init进程还用空环境exec getty程序。


正是getty为终端设备调用open。终端被打开来读和写。如果设备是一个猫,open可能在设备驱动里面延迟,直到猫被拨号及拨号被回答。一旦设备被打 开,文件描述符0、1和2被设置给设备。然后getty输出一些像login:的东西,然后等待我们输入我们的用户名。如果终端支持多重速度,getty 可以察觉用来改变终端速度(波特率)的特殊字符。参考你的UNIX系统手册来获得getty程序的更多细节,和可以驱动它的动作的数据文件 (gettytab)。


当我们输入我们的用户名,getty的工作便完成了,然后它接着调用login程序,类似于:
execle("/bin/login", "login", "-p", username, (char *)0, envp);


(在 gettytab文件里可以用让它调用其它程序的选项,但是默认是login程序。)init用一个空环境调用getty;getty用终端的名字(像 TERM=foo的东西,终端foo的类型从gettytab文件得到)和任何由gettytab指定的环境字符串来创建为login的一个环境。 login的-p标志告诉它保留它被传入的环境,和加入到那个环境而不是代替它。下面是在login被调用后的这些进程的状态:


1、进程ID为1的init进程读取/etc/ttys,为每个终端fork一次,创建空的环境变量;


2、每个子进程通过exec执行getty,打开终端设备(文件描述符0、1、2),读取用户名,初始环境集;


3、getty通过exec执行login。


上 面提到的所有进程都有超级用户权限,因为原始的init进程有超级用户权限。由进程ID 1 fork出来的进程init、getty和login都有相同的用户ID,因为进程ID通过一个exec不会被改变。同样,除了原始init进程的其它所 有进程的父进程ID都为1。


login程序做了许多事情。既然它有我们的用户名,它可以调用getpwnam来得到我们的密码文件项。然后 login调用getpass来显示提示Password:并读取我们的密码(当然,打印被关闭)。它调用crypt来加密我们输入的密码并把加密结果与 我们的影子密码文件项的pw_passwd域比较。如果登录尝试(在几次尝试后)因为一个无效密码失败,那么login调用参数为1的exit。这个终止 会被其父进程(init)注意到,而且它会执行另一个fork再执行一个getty的exec,为这个终端启动这个过程。


这是在UNIX系 统上使用的传统认证过程。当代UNIX系统已经进化到支持多个认证过程。例如,FreeBSD、Linux、Mac OS X和Solaris都支持一个名为PAM(Pluggable Authentication Modules,可插拔认证模块)的更灵活的设计。PAM允许一个管理员来配置访问服务使用的认证方法来,这些访问服务被编写以使用这个PAM库。


如果我们的应用程序想要验证一个用户有执行一个任务的恰当的权限,那么我们可以在应用程序里硬编码认证机制,或者使用PAM来得到等价的功能。使用PAM的好处是管理员可以配置为不同任务配置不同的认证用户的方法,基于本地策略。


如果我们成功登录,login将:


1、改变到我们的主目录(chdir);


2、改变我们终端设备的属主(chown)所以我们拥有它;


3、改变我们终端设备的访问权限,所以我们有读取它的权限;


4、通过调用setgid和initgroups来设置我们的组ID;


5、用login有的所有信息初始化环境:我们的主目录(HOME)、外壳(SHELL)、用户名(USER和LOGNAME)、和一个默认路径(PATH);


6、 改变到我们的用户ID(setuid)并调用我们的登录外壳,如execl("/bin/sh", "-sh", (char *)0); 作为argv[0]的第一个字符的负号是所有外壳的一个标志,标示它们被作为一个登录外壳被调用。这个外壳可以查看这个这个字符,并相应地修改它们的启 动。


login程序真正做的比我们在这描述的多。它选择性地打开当天消息文件,查看新的邮件,和执行其它任务。我们只对我们描述过的特性感兴趣。


从我们8.11节关于setuid函数的讨论里回想下,既然它被一个超级用户处理,setuid改变所有的三个用户ID:真实用户ID、有效用户ID和保存的设置用户ID。被login更早调用的setgid对所有三个组ID有相同的效果。


现在,我们的登录外壳在运行了。它的父进程ID是原始init进程(进程ID 1),所以当我们的登录外壳终止时,init被通知(它被发送了一个SIGCHLD信号),而它可以为这个终端再次开始一个完整的过程。文件描述符0、1、2为我们的登录外壳被设置为终端设备。


在所有事情为一个终端登录被设置好后的进程排列为:进程ID为1的init通过getty和login启动登录外壳;外壳为终端设备驱动打开描述符0、1、2;终端的用户通过硬线连接操作终端。


我 们的登录外壳现在读取它的启动文件(Bourne shell和Korn shell的.profile、GNU Bourne-again shell的.bash_profile、.bash_login或.profile文件;和C shell的.cshrc和.login)。这些启动文件通常改变一些环境变量并加入许多额外的变量到环境里。例如,多数用户设置他自己的PATH并经常 为真实的终端类型(TERM)提示。当启动文件被完成时,我们最终得到shell的提示并可以输入命令。


Mac OS X 终端登录

在Mac OS X上,终端登录处理遵从和在BSD登录处理里一样的步骤,因为Mac OS X是部分基于FreeBSD的。然而,在Mac OS X,我们在启动时用基于图形的登录屏幕显示。


Linux 终端登录

Linux登录过程和BSD过程非常相似。事实上,Linux的login命令由4.3BSD的login命令继承。BSD登录过程和Linux登录过程间的区别在于终端配置被指定的方法。

在 Linux上,/etc/inittab包含了配置信息,指定init应该为哪个终端设备启动一个getty处理,和在系统V上的方式相似。取决于被使用 的getty的版本,终端特性在命令行上(如agetty)或在文件/etc/gettydefs(如mgetty)里指定。


Solaris 终端登录

Solaris支持两种形式的终端登录:a、getty风格,如前面为BSD的描述,和b、ttymon登录,一个在SVR4引入的特性。通常,getty为控制台使用,而ttymon被用在其它登录上。


ttymon 命令是一个更大的术语为SAF(Service Access Facility,服务访问设施)的一部分。SAF的目标是提供一个一致的方法来管理提供系统访问的服务。为了我们的目的,我们和前面描述的进程的排列一 样,除了在init和登录外壳之间的不同的步骤集。init是sac(服务访问控制器)的父结点,sac执行一个fork和ttymon的exec,当系 统进入多用户状态时。ttymon程序监控所有列在配置文件里的终端端口,并当我们已经输入我们的用户名时执行一个fork。ttymon的子进程执行一 个login的exec,而login提示我们输入我们的密码。一旦这被完成,login exec我们的登录外壳,于是我们得到各前面一样的排列。一个区别是我们登录外壳的父进程现在是ttymon,而从getty登录的登录外壳的父进程是 init。

阅读(890) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~