《Linux/Unix系統編程手冊》讀書筆記5

《Linux/Unix系統編程手冊》讀書筆記 目錄html

第8章mysql

本章講了用戶和組,還有記錄用戶的密碼文件/etc/passwd,shadow密碼文件/etc/shadow還有組文件/etc/group。算法

每一個用戶都有惟一的用戶名和相關的用戶標識符(UID)。用戶能夠屬於一個或多個組,每一個組都有惟一的組名和相關的組標識符(GID)。sql

用戶和組的用途爲:一、能夠肯定各類系統資源的全部權;二、對賦予進程訪問上述資源的權限加以控制。shell

 

首先來看一下密碼文件/etc/passwd編程

lancelot@debian:~$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
messagebus:x:101:105::/var/run/dbus:/bin/false
colord:x:102:106:colord colour management daemon,,,:/var/lib/colord:/bin/false
usbmux:x:103:46:usbmux daemon,,,:/home/usbmux:/bin/false
Debian-exim:x:104:112::/var/spool/exim4:/bin/false
avahi:x:105:115:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
pulse:x:106:116:PulseAudio daemon,,,:/var/run/pulse:/bin/false
speech-dispatcher:x:107:29:Speech Dispatcher,,,:/var/run/speech-dispatcher:/bin/sh
hplip:x:108:7:HPLIP system user,,,:/var/run/hplip:/bin/false
sshd:x:109:65534::/var/run/sshd:/usr/sbin/nologin
rtkit:x:110:118:RealtimeKit,,,:/proc:/bin/false
statd:x:111:65534::/var/lib/nfs:/bin/false
saned:x:112:119::/home/saned:/bin/false
Debian-gdm:x:113:120:Gnome Display Manager:/var/lib/gdm3:/bin/false
lancelot:x:1000:1000:lancelot,,,:/home/lancelot:/bin/bash
mysql:x:114:121:MySQL Server,,,:/nonexistent:/bin/false
ftp:x:115:122:ftp daemon,,,:/srv/ftp:/bin/false
telnetd:x:116:124::/nonexistent:/bin/false

第一個字段是登陸名;第二個字段是通過加密後的密碼(x),實際上通過加密後的密碼是存放在shadow密碼文件;安全

第三個字段是用戶的ID(UID);第四個字段是組ID(GID);第五個字段是註釋;bash

第六個字段是主目錄,是用戶登陸後的初始路徑;第七個字段是登陸shell。ssh

接着來看實際存放密碼的shadow 密碼文件/etc/shadowide

格式以下:

lancelot:$6$tnTgvJYU$OhoUNZNIeNU7rlZf/f14oD2g.Uz8SbrnWeZbR4yL4XXRvzbCeijsAZE7Y9HlzU4thKVBVcqucwntJBi/4BoY60:15880:0:99999:7:::
mysql:!:15905:0:99999:7:::
ftp:*:16039:0:99999:7:::
telnetd:*:16180:0:99999:7:::

很明顯能夠看到第一個字段爲用戶登陸名,第二個字段爲見過加密後的密碼,後面的字段爲與安全性相關的字段。

看完用戶,咱們來看組文件/etc/group

lancelot@debian:~$ cat /etc/group
root:x:0:
daemon:x:1:
bin:x:2:
sys:x:3:
adm:x:4:
tty:x:5:
disk:x:6:
lp:x:7:
mail:x:8:
news:x:9:
uucp:x:10:
man:x:12:
proxy:x:13:
kmem:x:15:
dialout:x:20:
fax:x:21:
voice:x:22:
cdrom:x:24:lancelot
floppy:x:25:lancelot
tape:x:26:
sudo:x:27:
audio:x:29:pulse,lancelot
dip:x:30:lancelot
www-data:x:33:
backup:x:34:
operator:x:37:
list:x:38:
irc:x:39:
src:x:40:
gnats:x:41:
shadow:x:42:
utmp:x:43:telnetd
video:x:44:lancelot
sasl:x:45:
plugdev:x:46:lancelot
staff:x:50:
games:x:60:
users:x:100:
nogroup:x:65534:
libuuid:x:101:
crontab:x:102:
fuse:x:103:
scanner:x:104:saned,lancelot
messagebus:x:105:
colord:x:106:
lpadmin:x:107:
ssl-cert:x:108:
bluetooth:x:109:lancelot
utempter:x:110:
netdev:x:111:lancelot
Debian-exim:x:112:
mlocate:x:113:
ssh:x:114:
avahi:x:115:
pulse:x:116:
pulse-access:x:117:
rtkit:x:118:
saned:x:119:
Debian-gdm:x:120:
lancelot:x:1000:
mysql:x:121:
ftp:x:122:
vboxusers:x:123:
telnetd:x:124:

第一個字段是組的名稱,第二個字段是通過加密的密碼,第三個字段是組ID(GID),第四個字段是用戶列表。

對於加密後的密碼存放在相似/etc/shadow的文件(/etc/gshadow),格式以下:

cdrom:*::lancelot
floppy:*::lancelot
tape:*::
sudo:*::
audio:*::pulse,lancelot
dip:*::lancelot
www-data:*::
backup:*::
operator:*::
list:*::
irc:*::
src:*::
gnats:*::
shadow:*::
utmp:*::telnetd
video:*::lancelot

最後一個字段很明顯是用戶列表。

 

接着,咱們來看如何經過庫函數來獲取上面提到的信息。

1、從/etc/shadow獲取記錄:

1 #include <pwd.h>
2 
3 struct passwd *getpwnam(const char *name);
4 
5 struct passwd *getpwuid(uid_t uid);

getpwnam()是根據提供的登陸名返回一個指向對應的密碼記錄的指針。getpwuid()是根據提供的uid來返回一個指向對應的密碼記錄的指針。

若是出現錯誤返回NULL。

PS:對於getpwnam和getpwuid返回的指針都是指向由靜態分配而成的內存,所以都是不可重入。

這個應該是練習8-1的答案。

8-1:執行下列代碼時,將會發現,儘管這兩個用戶在密碼文件中對應不一樣的ID,但該程序的輸出仍是會將同一個數字顯示兩次。請問爲何?

printf("%ld %ld\n", (long)(getpwnam("avr")->pw_uid), (long)(getpwnam("tsr")->pw_uid));

書本的答案是這樣的:getpwnam()的調用在printf()輸出以前,那麼getpwnam()返回的結果存放在靜態分配的緩衝區中,第二個getpwnam()的返回結果會覆蓋第一個的結果。

而後我測試了一下,代碼以下:

 1 /*
 2  * =====================================================================================
 3  *
 4  *       Filename:  tt1.c
 5  *
 6  *    Description:  
 7  *
 8  *        Version:  1.0
 9  *        Created:  2014年04月22日 14時56分10秒
10  *       Revision:  none
11  *       Compiler:  gcc
12  *
13  *         Author:  alan (), alan19920626@gmail.com
14  *   Organization:  
15  *
16  * =====================================================================================
17  */
18 
19 #include <stdio.h>
20 #include <pwd.h>
21 
22 int main(int argc, char *argv[]){
23     printf("%ld %ld\n", (long)(getpwnam("lancelot")->pw_uid), (long)(getpwnam("root")->pw_uid));
24     return 0;
25 }
View Code

測試結果:

lancelot@debian:~/Code/tlpi$ ./a.out 
1000 0

而後整我的就凌亂了。。。。。。。。。。。。。。

後來,我把程序改爲這樣:

 1 #include <stdio.h>
 2 #include <pwd.h>
 3 
 4 int main(int argc, char *argv[]){
 5     struct passwd *p1, *p2;
 6     p1 = getpwnam("lancelot");
 7     p2 = getpwnam("root");
 8     printf("%ld %ld\n", p1->pw_uid, p2->pw_uid);
 9     //printf("%ld %ld\n", (long)(getpwnam("lancelot")->pw_uid), (long)(getpwnam("root")->pw_uid));
10     return 0;
11 }

才能輸出相同的值,由於兩個指針變量指向的地址是同樣的。可是以前那種是正確的,由於函數的參數是一值傳遞的方式傳遞,因此不存在題目說的兩個值相同。

後來我查找了做者的網站的磡誤:http://www.man7.org/tlpi/errata/index.html

發現這條題的題目修改了!!!!!!

這樣傳遞指針,兩個輸出的名字就是同樣的。。。。。。。。。。。。。。

下面是做者的解釋:

好吧,之後還要把書上的錯誤修改。。。。。。。

PS:再次證實無論例子多簡單也要試一試。。。。。

2、從/etc/group獲取記錄

1 #include <grp.h>
2 
3 struct group *getgrnam(const char *name);
4 
5 struct group *getgrgid(gid_t gid);

getgrnam根據提供的組名返回指向組的密碼記錄的指針,getgrigid則根據提供的組號GID返回該指針。失敗調用返回NULL

PS:這兩個函數也是不可重入的函數。

3、掃描密碼文件和組文件

1 #include <pwd.h>
2 
3 struct passwd *getpwent(void);
4 
5 void setpwent(void);
6 
7 void endpwent(void);

getpwent()能夠逐條返回記錄。setpwent()能夠重置爲。/etc/passwd文件的起始處。endpwent()能夠關閉文件。

4、從/etc/shadow密碼文件中獲取記錄

1 #include <shadow.h>
2 
3 struct spwd *getspnam(const char *name);
4 
5 struct spwd *getspent(void);
6 
7 void setspent(void);
8 
9 void endspent(void);

getspnam和getspent會返回指向shadow密碼記錄的指針,失敗調用返回NULL。

setspent會重置爲文件的起始位置,endspent會關閉文件。

5、密碼加密

1 #define _XOPEN_SOURCE
2 #include <unistd.h>
3 
4 char *crypt(const char *key, const key *salt);

#define _XOPEN_SOURCE 是爲了獲取crypt的聲明。

key爲輸入的密碼,salt指向一個兩字節的字符串,用來改變DES算法。成功調用返回加密後的密碼,失敗返回NULL。

 

---------------------吐槽:好好寫博客,寫博客的時候思考的感受真好,要多讀書,多code,多思考---------------------------

聽同窗說有不少厲害的人已經找到實習了,真的後悔大一大二的無做爲。正由於後悔,因此要作得更好!!!!

繼續努力!!!!!!

---------------------------------------------------------------------------------------------------------------------------------------------------

 

練習:

8-2: 使用sptwent()、getpwent()和endpwent()來實現getpwnam()。

這題我的以爲很簡單,由於getpwent()是逐條查找,查找匹配就輸出。輸出完應該調用sptwent將文件的偏移量重置爲文件的起始位置。結束的時候調用endpwent關閉文件。

 1 /*
 2  * =====================================================================================
 3  *
 4  *       Filename:  8-2.c
 5  *
 6  *    Description:  
 7  *
 8  *        Version:  1.0
 9  *        Created:  2014年04月22日 16時48分09秒
10  *       Revision:  none
11  *       Compiler:  gcc
12  *
13  *         Author:  alan (), alan19920626@gmail.com
14  *   Organization:  
15  *
16  * =====================================================================================
17  */
18 
19 #include <pwd.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include "tlpi_hdr.h"
23 
24 struct passwd * Getpwnam(const char *name){
25     struct passwd *pwd;
26     while((pwd = getpwent()) != NULL){
27         if(strcmp(pwd->pw_name, name) == 0){
28             setpwent();
29             return pwd;
30         }
31     }
32     setpwent();
33     return NULL;
34 }
35 
36 int main(int argc, char *argv[]){
37     int i;
38     struct passwd *p;
39     if(argc < 2 || strcmp(argv[1], "--help") == 0)
40         usageErr("%s user-names...", argv[0]);
41 
42     for(i = 1; i < argc; ++i){
43         p = Getpwnam((const char *)argv[i]);
44         if(p == NULL)
45             printf("%s does not exit\n", argv[i]);
46         else{
47             printf("%s, UID: %ld, GID: %ld\n", argv[i], (long)p->pw_uid, (long)p->pw_gid);
48         }
49     }
50     
51     endpwent();
52     exit(EXIT_SUCCESS);
53 }

測試結果:

lancelot@debian:~/Code/tlpi$ ./a.out lancelot root
lancelot, UID: 1000, GID: 1000
root, UID: 0, GID: 0
相關文章
相關標籤/搜索