在UNIX多用户系统中,资源的访问控制取决于用户组、用户名以及相应的读写权限,管理员由此可以规划出较为安全的系统环境。然而,系统似乎对注册的站点限制这一十分有效的安全措施有所忽视,也未提供象NetWare那样简洁的注册站限制管理手段。为此,笔者设计了一个用户注册站限制程序,保证了用户必须在指定的终端上方能成功登录,从而使UNIX多用户系统的注册安全性得到了进一步的加强。本功能实现的基本原理为:首先获取终端的用户注册信息,然后与用户注册限制文本中该号终端项的内容相比较,若该终端上不具备此用户的注册权限,则将其用户进程杀出。UNIX的开发环境为程序员提供多种获取用户进程的手段,其中utmp类文件为象who、write、和log那样的命令保存了较为完整的用户信息和记帐信息,相对而言,读取此类文件是最为直接而且高效的方法。在utmp。h头文件中,定义了utmp类文件的结构,内容如下:
struct utmp{ char ut-user[8]; /*用户的注册名*/ char ut-id[4]; /*/etc/inittab的ID,*/ char ut-line[12]; /*设备名(控制台,lnxx)*/ short ut-pid;/*进程ID*/ short ut-type; /*表项的类型*/ short exit-status{ shar e-termination; /*进程结束状态*/ shar e-exit; /*进程出口状态*/}ut-exittime-t ut-time;/*形成时间项*/}其中,当ut-type的值等于7的时候,表示该进程为一个用户进程,在头文件中对ut-type还有如下的定义:
#define USER-PROCESS 7利用getutent()函数可以方便地从utmp类的文件中读入下一项的内容,其返回一个指向utmp结构的指针。如果这个文件尚未打开,则getutent()自动地打开这个文件,如果到了文件的末尾,则失败。因为检索的是整个文件,所以在搜索新的文件项之前需调用setutent()函数把输入流复位到文件头。注册限制的具体内容存放在文本文件/etc/login。cfg中,除超级用户外的其它用户对此文件不具备读写权限。每条限制项包括终端号和用户名两项内容,其中用户名前带+为"允许",带-为"禁止",省略用户名为"不限制"。假设有如下设置: tty1a +cwgl xsgl tty1b -ckgl tty1c ………则表示终端tty01允许注册cwgl和xsgl两用户,终端tty02禁止ckgl用户注册,终端tty03允许所有用户注册。对于非法用户进程,可发sigkill信号杀出。值得注意的是,杀用户进程时应有一个适当的延时。编译后的可执行文件在系统引导后由超级用户执行。
本程序已经在一些基于SCO UNIX操作系统的大中型企业MIS中实际应用,取得了良好的效果。
/*源程序清单 */#include<signa1。h>#include<stdio。h>#include<string。h>#include<utmp。h>#define AND &&#define OR ||main(){FILE *fp; struct utmp*utmp-p,utmp-old; char cfgbuf[1024];if((fp=fopen(″/etc/login。cfg″,″r″))==NULL)printf(″Can't open login。cfgfile!\n″);return;}while(1){setutent();while(1){utmp-p=getutent();if(utmp-p==NULL)break;if(utmp-p->ut-type==USER-PROCESS){sleep(2);fseek(fp,0L,0);do{if(fgets(cfgbuf,1024,fp)==NULL){cfgbuf[0]=`\0'break;}}
while(strncmp(utmp-p->ut-line,cfgbuf,strlen(utmp-p->ut-line)));if(*cfgbuf){cfgbuf[strlen(cfgbuf)-1]=`\0';if(!checkperm(cfgbuf,utmp-p->ut-user)){printf(″Kill %s to %s!\n″,utmp-p->ut-line,utmp-p->ut-user);kill(utmp-p->ut-pid,SIGKILL);utmp-old=*utmp-p;do{setutent();utmp-p=getutline(&utmp-old);}while(utmp-p->ut-type!=LOGIN-PROCESS);}}}}endutent();}return;}checkperm(cfgline,user)char *cfgline,user;/*功能:登录权限检查*/{int flag;char *p;if(!strpbrk(cfgline,"+-"))flag=1;else{if(strchr(cfgline,`+'))flag=0;else flag=1;if(strstr(cfgline,user))flag=!flag;}return flag;}
|