讀書筆記——《UNIX環境高級編程》第六章_系統數據文件和信息

 

第六章 系統數據文件和信息

系統正常運行需要使用大量系統數據文件,其中,所有UNIX系統都有的是:口令文件、組文件,大多數系統都提供的是:登錄賬戶記錄、系統標識、時間和日期例程同時還有其他一些常用系統數據文件如:BSD網絡軟件有一個記錄各網絡服務器所提供服務的數據文件(/etc/services)、記錄協議住處的數據文件(etc/protocols)等。

現在來按這個順序討論這些文件。

1、口令文件

口令文件包括了以下字段,這些字段包含在<pwd.h>中定義的passwd結構中:

說明

struct passwd成員

用戶名

char *pw_name

加密口令

char *pw_passwd

數值用戶ID

uid_t pw_uid

數值組ID

gid_t pw_gid

註釋字段

char *pw_gecos

初始工作目錄

char *pw_dir

初始shell(用戶程序)

char *pw_shell

用戶訪問類

char *pw_class

下次更改口令時間

time_t pw_change

賬戶到期時間

time_t pw_expire

由於歷史原因,口令文件存儲在/etc/passwd中,並且是一個ASCII文件。每一行表示上表的各個字段,字段之間用冒號分隔。例如按照上面的字段順序,passwd文件中可能會有如下內容:

squid:x:23:23::/var/spool/squid:/dev/null

sar:x:205:105:Litingli:/home/sar:/bin/bash

注:

l  如果是root用戶,則其用戶數值ID0

l  口令文件項中某些字段可以爲空

l  shell字段包含一個可招待程序名,它被用於用戶登錄shell,若該字段爲空,則取系統默認值。注意到squidshell字段被設置爲/dev/null這是一個設備,不能執行,這樣做的目的是阻止任何人以用戶squid的名義登錄到該系統

         某些UNIX系統提供finger(1)命令可用於查看註釋字段中的信息,如對於以下記錄:

         sar:x:205:105:Litingli,scu,88-8888,66-6666:/home/sar:/bin/bash

         註釋字段的各個信息以逗號隔開:用戶姓名,辦公地點,辦公電話,家庭電話等,使用finger(1)命令就可以打印註釋字段中的信息:

         #finger –p sar

         Login:sar                                                          Name:Litingli

         Directory:/home/sar                                    Shell:/bin/sh

         Office:88-8888                                               Home Phone:66-6666

         On since Mon Jan 19 03:57 (EST) on ttyv0 (message off)

         No mail

1.1查詢口令文件

查詢口令文件有兩種方式:一種僅查詢特定用戶的記錄,一種是查詢文件中所有記錄。

                   對於特定用戶的查詢,可以使用以下函數完成:

                            #include <pwd.h>

                            struct passwd *getpwuid(uid_t uid);                     //通過用戶ID查詢

                            struct passwd *getpwnam(const char* name);                   //通過用戶名查詢

                   對於所有記錄的查詢,可能使用以下函數完成:

                            #include <pwd.h>

                            struct passwd *getpwent(void);

                            void setpwent(void);

                            void endpwent(void);

調用getpwent時,返回口令文件中的下一個記錄;setpwent反繞它所使用的文件,所謂反繞,是指使getpwent指向口令文件的開頭,使其回到起點讀取;最後,一定要使用endpwent關閉這些文件。

                  1.2編輯口令文件

某些系統提供vipw命令,允許管理員使用該命令編輯口令文件,此命令串行化對口令文件所做的修改(有點類似於鎖的概念,串行化後,不會存在同時多個對口令文件的寫操作),並確保所做的更改與其他相關文件保持一致。

 

2、陰影口令

之所以加入陰影口令,是出於安全的考慮,因爲加密口令是經單向加密算法處理用戶口令副本,由於其不可逆性,因此不能夠將加密口令經過逆向算法還原成明文口令,但是這樣也不能防止一些不法份子來猜口令,只要通過單向加密算法將猜測的明文口令變換成加密形式,然後將其與合法用戶的加密口令對比,即可猜出(譬如不法份子可以申請一個賬戶,然後不斷地修改其口令,每次修改後都查看一下口令文件中被加密的口令,看是否和合法用戶的加密口令一樣,那麼他就找到了合法用戶的明文口令了)。

可以發現,上面之所以不法份子能猜到合法用戶的口令,是因爲他可以查看口令文件中的加密口令,然後和他自己口令的加密形式來對比,就能猜出合法用戶的口令。所以,只要將加密口令隱藏起來,使其無法獲得原始資料,不法份子也就沒法比較了。

這是就引入陰影口令的原因,現在我們將加密口令存放於陰影口令文件,而非前面提到的口令文件。陰影口令文件不是一般用戶可以讀取的,例如login(1)passwd(1),這些函數必須要用戶IDroot才能存取加密口令,所以就樣就能很好的保護好“原始資料”。

明白了其工作原理,來看看其細節。陰影口令文件至少要包括用戶名和加密口令。與該口令相關的其他信息也可存放在該文件中。在Linux2.4.22Solaris 9中,有一組函數可以訪問口令文件(其實這和前面查看口令文件的函數類似):

#include <shadow.h>]

struct spwd *getspnam(const char *name);

struct spwd *getspent(void);

 

void setspent(void);

void endspent(void);

FreeBSD5.2.1MAC OS X10.3中,沒有陰影口令結構。

 

3、組文件

         UNIX組文件包含了以下字段:  

說明

struct group成員

組名

char *gr_name

加密口令

char *gr_passwd

數值組ID

int gr_gid

指向各用戶名的指針數組

char **gr_mem

         同口令文件一樣,組文件也分爲兩種查詢方式:

                  對於特定組的查詢可用以下函數:

                            #include <grp.h>

                            struct group *getgrgid(gid_t gid);

                            struct group *getgrnam(const char *name);

                   對於整個組文件的查詢,可用以下三個函數,功能與口令文件的類似:

                            #include <grp.h>

                            struct group *getgrent(void);

                           

                            void setgrent(void);

                            void endgrent(void);

 

4、附加組ID

爲什麼會出現一個附加組ID?這次和陰影口令不一樣,並非出於安全的考慮。在傳統UNIX中,每個用戶任何時候只能屬於一個組,當用戶登錄時,系統就會去查看口令文件中“數值組ID”這項,然後將此組ID賦於用戶實際組ID(有點類似於一個人只能有一種國籍,要麼是中國國籍,要麼就是別國國籍)。這種組成員形式一直維持到1983年左右,後來在BSD4.2中引入了附加組ID,用戶不僅可以屬於口令文件中記錄的組ID,而且還可以屬於其他的組(這就類似於一個人在取得中國國籍之後,還可以取得其他國家的國籍)。

附加組ID的優點在於:不必顯式地經常更改組。可以通過以下三個函數來獲取和設置組ID

#include <unistd.h>

int getgroups(int gidsetsize, gid_t grouplist[]);

 

#include <grp.h>

#include <unistd.h>

int setgroups(int ngroups, const gid_t grouplist[]);

         int initgroups(const char *username, gid_t basegid);

         對於這些函數不再做過多說明。

 

 

 

 

另外,需要說明的是,在很多系統中,用戶和組數據庫是用網絡信息服務(Network   Information Service ,NIS)實現的,這使管理員可編輯數據庫的主副本,然後將它分發到組織中的所有服務器上,客戶端系統可以聯繫服務器以查看用戶和組的有關信息。

 

5、登錄賬戶記錄

         大多數UNIX系統者提供下列兩個數據文件:utmpwtmp文件,分別用於記錄當前登錄進系統的各個用戶,跟蹤各個登錄、註銷事件。在V7中,這兩個文件都包含如下結構:

         struct utmp{

                   char ut_line[8];                 /*tty line: “ttyh0”,”ttyd0”,”ttyp0”,*/

                   char ut_name[8];           /*login name*/

                   long ut_time;                    /*seconds since Epoch*/

         };

         登錄時,login程序填寫此類型結構,然後將其寫入到utmp文件中,同時也添寫其  wtmp文件中;註銷時,init進程將utmp文件中相應的記錄擦除(每個字節都填爲0),並將一個新記錄添寫到wtmp文件中,在wtmp文件的註銷記錄中,將ut_name字段清0在系統重啓、更改系統時間和日期前後,都在wtmp文件中添寫特殊的記錄項。

         who(1)程序讀utmp文件,並以可讀格式打印其內容;後來的UNIX版本提供了last(1)命令,它讀wtmp文件並打印所選擇的記錄。

 

6、系統標識

         可以通過uname函數得到當前主機和操作系統的有關信息:

                   #include <sys/utsname.h>

                   int uname(struct utsname *name);

         該函數所用的數據結構如下(下面列出的只是POSIX.1定義的至少需要的字段,某些實現在該結構中提供了另外一些字段):

                   struct utsname{

                            char sysname[];               /*name of OS*/

                            char nodename[];           /*name of this node*/

                            char release[];                  /*current release of operating system*/

                            char version[];                 /*current version of this release*/

                            char machine[];                /*name of the hardware type*/

                   };

         另外,BSD系統提供了gethostname函數(目前它已是POSIX.1的一部份),它只返回主機名,該名字通常是TCP/IP網絡上主機的名字。

         當然除了可以獲取主機名之外,我們還需要設置主機名,hostname(1)命令可以二者都實現,超級用戶則可以使用一個類似的函數sethostname用於設置主機名。

 

7、時間和日期例程

         UNIX內核提供的基本時間服務是計算處國際標準時間公元197011000000以來經過的秒數,它是用數據類型time_t表示的,我們稱其爲日曆時間:包括日期和時間。

         time函數可以返回當前時間和日期:

                   #include <time.h>

                   time_t time(time_t *calptr);

         time函數相比,gettimeofday提供了更高的分辨率(最高爲微秒級):

                   #include <sys/time.h>

                   int gettimeofday(struct timeval *restrict tp, void *restrict tzp);

         其中,結構timeval定義如下:

                   struct timeval{

                            time_t     tv_sec;    

                            long      tv_usec;            /*microseconds*/

                   };

         一旦獲得這種以秒計的整型時間值後,通常要調用另一個時間函數將其轉換爲人們可讀的時間和日期,下圖說明了各個函數之間的關係:

 

 

                                                                        

 

 

         結構tm定義如下(注意每個成員的範圍):

                   struct tm{                                    /*a broken-down time*/

                            int tm_sec;                        /*seconds after the minute:[0-60]

                            int tm_min;                       /*minutes after the hour:[0-59]

                            int tm_hour;                      /*hours after midnight:[0-23]*/

                            int tm_mday;                    /*day of the month[1-31]*/

                            int tm_mon;                      /*months since January[0-11]*/

                            int tm_year;                      /*years since 1900*/

                            int tm_wday;                    /*days since Sunday:[0-6]*/

                            int tm_yday;                      /*days since January 1:[0-365]*/

                            int tm_isdst;                     /*datlight saving time flag:<0,0,>0*/

                   };

 

8、其他數據結構

         在開頭,已經提到了還有一些其他常用的數據文件,如:BSD網絡軟件有一個記錄各網絡服務器所提供服務的數據文件(/etc/services)、記錄協議住處的數據文件(etc/protocols)等。幸運的是,針對這些數據的端口都與口令文件和組文件接口相似

1、  set函數,打開相應數據文件,然後反繞該文件。

2、  end函數,關閉相應數據文件。

 

發佈了22 篇原創文章 · 獲贊 24 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章