1. 程式人生 > >Linux下如何讓普通使用者執行特權程式訪問受限檔案

Linux下如何讓普通使用者執行特權程式訪問受限檔案

問題: 如下這個檔案,由root賬號建立,許可權為 rw-r-----,即對普通使用者來說,read/write許可權都沒有.

-rw-r-----  1 root   root         0 7月   9 21:22 rootfile

在非root賬號即普通使用者賬號下,試圖讀取該檔案會報錯:

$ cat rootfile 
cat: rootfile: 許可權不夠

在某些特殊情況下,普通使用者也需要讀取該檔案的內容.怎麼辦?

解決辦法:

1. 編寫一個owner id為root的程式,讀寫rootfile,名為 ReadRootFile(原始碼見下文 )。此時該程式只能由root賬號執行。

-rwxr-xr-x  1 root   root      8968 7月   9 21:37 ReadRootFile

   如果嘗試在普通賬號下執行該程式,會報錯:

$ ./ReadRootFile rootfile 
Open fail: : Permission denied
Real User ID:1000, name=liuwei
Effective User ID:1000, name=liuwei

2. 在root賬號下,執行 chmod u+s ./ReadRootFile,開啟 Set-User-ID 位。設定後,再次檢視檔案屬性。可見檔案的使用者可執行許可權位變成了s,表示修改成功。

$ sudo chmod u+s ./ReadRootFile
$ ls -l ReadRootFile
-rwsr-xr-x 1 root root 8968 7月   9 21:37 ReadRootFile

3. 切換到普通賬號,再次執行 ./ReadRootFile,成功開啟rootfile.

$ ./ReadRootFile ./rootfile 
Open ./rootfile ok.
Real User ID:1000, name=liuwei
Effective User ID:0, name=root

注意第1步和第3步前後對比,Effective User ID和Name發生了變化.

原理解釋:

首先說明幾個概念.

Owner ID:  檔案的擁有者,即我們通過 ls -l 看到的名字.ReadRootFile的Owner ID為root.

Real User ID:  程序的實際使用者ID,我們在哪個賬戶下執行該程序,那程序的Real User ID就是這個賬戶.

Effective User ID: 程序的有效使用者ID. 預設情況下,Effective User ID等於Real User ID.但通過chmod u+s設定了Set-User-ID後,Effective User ID就等於程序的Owner ID.

如果程序的Effective User ID與檔案的Owner ID相同,則該程序有許可權訪問該檔案。應用至Group同樣成立。

本來rootfile只能允許root和root組賬戶才能訪問,但執行上面第2步後,在普通賬戶liuwei下執行./ReadRootFile,此時程序的Effective User ID變成了ReadRootFile的Owner ID,即root。因此,也可以成功訪問rootfile。

ReadRootFile.c:

/*
 * getuid() returns the real user ID of the calling process.
 * geteuid() returns the effective user ID of the calling process.
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <pwd.h>
#include <grp.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>

char * get_username_by_id(uid_t uid)
{
    struct passwd *pwd;

    pwd = getpwuid(uid);
    return (pwd == NULL) ? NULL : pwd->pw_name;
}

int main(int argc, char *argv[])
{
	int fd;

	fd = open(argv[1], O_RDWR);
	if(fd == -1)
		perror("Open fail: ");
	else
		printf("Open %s ok.\n", argv[1]);

	printf("Real User ID:%d, name=%s\n",
		getuid(), get_username_by_id(getuid()));
	/* 如果設定了Set-User-ID(chmod u+s),那Effective User ID與Owner ID相同。 */
	printf("Effective User ID:%d, name=%s\n",
		geteuid(), get_username_by_id(geteuid()));

	close(fd);

	return 0;
}