1. 程式人生 > >Apache下root許可權執行CGI

Apache下root許可權執行CGI

問題場景

Apache預設是以daemon使用者(或者其他other使用者)和daemon使用者組啟動的,所以其worker程序也是daemon許可權的,這樣,worker程序fork的CGI程序,以及CGI再fork的子程序,都是daemon許可權的。如果想在CGI或者CGI子程序中操作一些需要root許可權的檔案或者命令,就會報許可權錯誤。
Apache其實也可以通過root許可權來啟動,需要在編譯時加入特定選項,而且配置中的User和Group都修改成root,但是Apache強烈建議不要這麼做,應該是出於安全考慮。
那麼怎麼解決非root使用者啟動的Apache的CGI程序可以訪問需要root許可權才能訪問的資源呢?

解決方法

宣告:本方法根據網上一些方法整理而來,經驗證有效。

  • 在root許可權下編寫並編譯你的CGI;
  • 在你的CGI開始的時候新增如下程式碼:
...
uid_t uid = getuid();//獲取當前程序的user id
uid_t euid = geteuid();//獲取當前程序的effective user id
//euid應該為0,即root許可權
printf("befor setreuid uid: %u, euid: %u\n", uid, euid);
if (setreuid(euid, uid)) {//交換有效使用者ID和實際使用者ID
     perror("setreuid"
); return -1;//出錯的話還是儘早返回吧,否則後面也會報許可權錯誤 } //此時的uid應該為0,擁有了root許可權 printf("after setreuid uid: %u, euid: %u\n", getuid(), geteuid()); ...
  • 對編譯出來的二進位制CGI檔案加s許可權,並拷貝到Apache的CGI執行目錄;
chmod +s your_program.cgi
  • 這樣應該就可以了。(不行的話還有別的辦法)

簡單測試

  • 首先,假設有一個需要root許可權才能執行的檔案
    root許可權可執行a.out
  • 在root許可權下編寫需要訪問a.out的程式test_v1.cpp
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    uid_t uid ,euid;

    uid = getuid();
    euid = geteuid();

    printf("my uid :%u\n", uid);
    printf("my euid :%u\n", euid);

    system("/home/guest/a.out");
    return 0;
}
  • root許可權編譯,guest許可權執行
    test_v1

    可以看到當前uid和euid都是other許可權的,訪問a.out時許可權受限

  • 在root許可權對檔案test_v1加s許可權後,guest許可權再次執行
    這裡寫圖片描述
    這裡寫圖片描述

    可以看到,此時的euid已經變成root許可權的了,但是還是無法訪問a.out

  • 修改test_v1程式碼,修改後test_v2.cpp如下
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    uid_t uid ,euid;

    uid = getuid();
    euid = geteuid();

    printf("my uid :%u\n", uid);
    printf("my euid :%u\n", euid);
    if(setreuid(euid, uid))//交換有效使用者ID和實際使用者ID
        perror("setreuid");
    printf("after uid :%u\n", getuid());
    printf("after euid :%u\n", geteuid());

    system("/home/polli/test/a.out");
    return 0;
}
  • 在root許可權編譯test_v2, 並加s許可權,guest許可權執行test_v2
    這裡寫圖片描述

    可以看到交換許可權後,uid變為root許可權,可以正常執行a.out

參考連結