Linux進程編程介紹(三)

來源:互聯網
上載者:User
摘要:本節要介紹一些有關進程的特殊操作。有了這些操作,就使得進程的編程更加完善,能編製更為實用的程式。主要的內容有得到關於進程的各種ID、對進程的設定使用者ID、改變進程的工作目錄、改變進程的根、改變進程的優先權值等操作。
  
  3.進程的特殊操作
  
    上一節介紹了有關進程的一些基本操作,如進程的產生、進程的終止、進程執行映像的改變、等待子進程終止等。本節要介紹一些有關進程的特殊操作。有了這些操作,就使得進程的編程更加完善,能編製更為實用的程式。
  
    主要的內容有得到關於進程的各種ID、對進程的設定使用者ID、改變進程的工作目錄、改變進程的根、改變進程的優先權值等操作。
  
  3.1 獲得進程相關的ID
  
    與進程相關的ID有:
  
  真正使用者標識號(UID):該標識號負責標識運行進程的使用者。
  有效使用者標識號(EUID):該標識號負責標識以什麼使用者身份來給新建立的進程賦所有權、檢查檔案的存取許可權和檢查通過系統調用kill向進程發送非強制中斷訊號的許可許可權。
  真正使用者組標識號(GID):負責標識運行進程的使用者所屬的組ID。
  有效使用者組標識號(EGID):用來標識目前進程所屬的使用者組。可能因為執行檔案設定set-gid位而與gid不同。
  進程標識號(PID):用來標識進程。
  進程組標識號(process group ID):一個進程可以屬於某個進程組。可以發送訊號給一組進程。注意,它不同與gid。前面的系統調用wait中指定參數pid時,就用到了進程組的概念。
    如果要獲得進程的使用者標識號,用getuid調用。調用geteuid是用來獲得進程的有效使用者標識號。有效使用者ID與真正使用者ID的不同是由於執行檔案設定set-uid位引起的。這兩個調用的格式如下:
  
    uid_t getuid(void);
    uid_t geteuid(void);

    在使用這兩個調用的程式中加入下列標頭檔:
  
    #include
    #include
  
    如果要獲得運行進程的使用者組ID,使用getgid調用來獲得真正的使用者組ID,用getegid獲得有效使用者組ID。標識gid與egid的不同是由於執行檔案設定set-gid位引起的。這兩個調用的格式如下:
  
    gid_t getgid(void);
    gid_t getegid(void);
  
    在使用這兩個調用的程式中加入下列標頭檔:
  
    #include
    #include
  
    如果要獲得進程的ID,使用getpid調用;要獲得進程的父進程的ID,使用getppid調用。這兩個調用的格式如下:
  
    pid_t getpid(void);
    pid_t getppid(void);
  
    在使用這兩個調用的程式中加入下列標頭檔:
  
    #include
  
    如果要獲得進程所屬組的ID,使用getpgrp調用;若要獲得指定PID進程所屬組的ID用getpgid調用。這兩個調用的格式如下:
  
    pid_t getpgrp(void);
    pid_t getpgid(pid_t pid);
  
    在使用這兩個調用的程式中加入下列標頭檔:
  
    #include
  
    注意一下gid和pgrp的區別,一般執行該進程的使用者的組ID就是該進程的gid,如果該執行檔案設定了set_gid位,則檔案所屬的組ID就是該進程的gid。對於進程組ID,一般來說,一個進程在shell下執行,shell程式就將該進程的PID賦給該進程的進程組ID,從該進程派生的子進程都擁有父進程所屬的進程組ID,除非父進程將子進程的所屬組ID設定成與該子進程的PID一樣。由於這幾個調用使用很簡單,這裡就不再舉例。
  
  3.2 setuid 和 setgid 系統調用
  
    前面講述了如何得到uid和gid,現在來看看如何設定它們。在講述這兩個調用以前我們先來看看對檔案設定set_uid位會有什麼作用。我們先編了一個小程式來做實驗。這個程式的作用是,列印出進程的uid和euid,然後開啟一個名為tty.c的檔案。如果打不開,就顯示錯誤碼;如果開啟了,就顯示開啟成功。假設該程式名叫uid_test.c:

    /* uid_test.c */
    #include
    #include
    #include
    #include
    #include
    #include
    extern int errno;
  
    int main()
    {
    int fd;
    printf("This process's uid = %d, euid = %d ",getuid(),geteuid());
    if ((fd = open("tty.c",O_RDONLY))==-1)
    {
      printf("Open error, errno is %d ",errno);
      exit(1);
    }
    else
    {
      printf("Open success ");
    }
    }
  
    下面列出這幾個檔案的目錄,可以看到檔案tty.c的存取許可權僅為屬主root可讀寫。
  
    [wap@wapgw /tmp]$ ls -l
    total 3
    -rw------- 1 root root 0 May 31 16:15 tty.c
    -rwxr-xr-x 1 root root 14121 May 31 16:15 uid_test
    -rw-r--r-- 1 root root 390 May 31 16:15 uid_test.c
    [wap@wapgw /tmp]$
  
    在該系統中的使用者中個使用者wap(500),以root使用者身份執行程式:
  
    [root@wapgw /tmp]# ./uid_test
    This process's uid = 0, euid = 0
    Open success
    [root@wapgw /tmp]#
  
    下面使用su命令,轉到使用者wap下,執行程式
  
    [root@wapgw /tmp]#su wap
    [wap@wapgw /tmp]$ ./uid_test
    This process's uid = 500, euid = 500
    Open error, errno is 13
    [wap@wapgw /tmp]$
  
    這是由於進程的uid是500(wap),對檔案tty.c沒有存取權,所以出錯。
  
    給程式檔案設定set-uid位
  
    [root@wapgw /tmp]# chmod 4755 uid_test
  
    再轉到使用者wap下,執行程式uid_test。
  
    [wap@wapgw /tmp]$ ./uid_test
    This process's uid = 500, euid = 0
    Open success
    [wap@wapgw /tmp]$
  
    從上面我們看到,進程列印出的euid是0(root),而運行該進程的使用者是500(wap)。由於進程的euid是root,所以成功開啟了檔案tty.c。
  
    上面的例子說明了兩個事實:第一,核心對進程存取檔案的許可權的檢查,是通過檢查進程的有效使用者ID來實現的;第二,執行一個設定set_uid位的程式時,核心將進程表項中和u區中的有效使用者ID設定為檔案屬主的ID。為了區別進程表項中的euid和u區中的euid,我們將進程表項中的euid 域稱為儲存使用者標識號(saved user ID)。
  
    下面我們來看看這兩個調用。調用的聲明格式如下:
  
    int setuid(uid_t uid);
    int setgid(gid_t gid);
  
    在使用這兩個調用的程式中加入下面的標頭檔:
  
    #include
  
    調用setuid為當前發出調用的進程設定真正和有效使用者ID。參數uid是新的使用者標識號(該標識號應該在/etc/passwd檔案中存在)。如果發出調用的進程的有效使用者ID是超級使用者,核心將進程表中和u區中的真正使用者標識號和有效使用者標識號置為參數uid。如果發出調用的進程的有效使用者識別碼而不是超級使用者,那麼核心將根據指定的參數uid來執行,如果這時指定的參數uid的值是真正使用者標識號或者是儲存使用者標識號(saved user ID),則核心將u區中的有效使用者標識號改為參數uid,否則,該調用返回錯誤。該調用成功時,傳回值為0;發生錯誤時,返回-1,並設定相應的錯誤碼 errno,下面是經常可能發生的錯誤碼:
  EPERM:使用者不是超級使用者,並且指定的參數uid與發出調用的進程的真正使用者ID或儲存使用者ID不匹配。
    調用setgid設定當前發出調用的進程的真正、有效使用者組ID。該調用允許進程指定進程的使用者組ID為參數gid,如果進程的有效使用者ID不是超級使用者,該參數gid必須等於真正使用者組ID、有效使用者組ID中的一個。如果進程的有效使用者ID是超級使用者,可以指定任何存在的使用者組ID(在 /etc/group檔案中存在)。
  
    注意: 對於setuid程式尤其要小心,當進程的euid是超級使用者時,如果將進程setuid到其他使用者,就無法再得到超級使用者的權力。我們可能這樣用這個調用,某個程式,開始需要root權力才能完成開始的工作,但後續的工作不需要root的權力,所以,我們將程式的執行檔案設定set_uid位,並使得執行檔案的屬主是root,這樣進程開始時,就具有了root的許可權,在不再需要root許可權的地方,用setuid(getuid)恢複進程的uid、 euid。對於可執行檔設定set_uid位,一定要注意,尤其是對那些屬主是root的更要注意。因為LINUX系統中root擁有任何權力。使用不當,會對系統安全有極大的損害。
  
  3.3 setpgrp和setpgid 系統調用
  
    這兩個調用是用來設定進程組ID的,其聲明格式如下:
  
    int setpgrp(void);
    int setpgid(pid_t pid, pid_t pgid);
  
    在使用這兩個調用的程式中加入下面的標頭檔:
  
  #include
  
    調用setpgrp用來將發出調用的進程的進程組ID設定成與該進程的PID相等。注意,以後由這個進程派生的子進程都擁有該進程組ID(除非修改子進程的進程組ID)。
  
    調用setpgid用來將進程號為參數pid的進程的進程組ID設定為參數pgid。如果參數pid為0,則修改發出調用進程的進程組ID。如果參數pgid為0,將進程號為pid的進程改為與發出調用的進程同組。如果不是超級使用者發出的調用,那麼被指定的進程必須與發出調用的進程有相同的 EUID,或者被指定的進程是發出調用進程的子進程。
  
    進程組可用於訊號的發送,或者終端輸入的仲裁(與終端控制進程有相同的進程組ID且在前台可以讀取終端,其他進程在企圖讀的時候被阻塞並發送訊號給該進程)。
  
    該調用成功時,傳回值為0;如果請求失敗,返回-1,並設定全域變數errno為對應的值。下面是可能遇到的錯誤碼:
  
  ESRCH:參數pid指定的進程不存在。
  EINVAL:參數pgid小於0。
  EPERM:指定進程的EUID與發出調用進程的euid不同,且指定進程不是發出調用進程的子進程。
  3.4 chdir 系統調用系統調用
  
    chdir是用來將進程的當前工作目錄改為由參數指定的目錄。該調用的聲明格式如下:
  
    int chdir(const char *path);
  
    在使用該調用的程式中加入下面的標頭檔:
  
    #include
  
    使用該調用時要注意,發出該調用的進程必須對參數path指定的目錄有搜尋(execute)的權力。調用成功時,傳回值為0;錯誤時,返回-1,並設定相應的錯誤碼。
  
  3.5 chroot 系統調用
  
    系統調用chroot用來改變發出調用進程的根(“/”)目錄。該調用聲明的格式如下:
  
    int chroot(const char *path);
  
    在使用該調用的程式中加入下面的標頭檔:
  
    #include
  
    調用chroot將進程的根目錄改到由參數path所指定的地方。以後該進程中以“/”(根)開始的路徑,都從指定目錄處開始尋找。發出調用進程的子進程都繼承這個根目錄的位置。該調用只能由超級使用者(root)發出。注意,該調用並不改變當前工作目錄,所以有可能當前工作目錄“.”在根目錄“/” 之外。調用成功時,傳回值為0;錯誤時,返回-1,並設定相應的錯誤碼。
  
    注意: 如果用chroot調用改變根後,不能由調用chroot(“/”)來返回真正的根,因為調用中的參數“/”會被理解成新設定的根。該調用一般可以用在 login程式中,或者現在國內常見的BBS系統等應用程式中,使用者登入後執行系統的一個程式,該程式將根改變成使用者登入的目錄(例如 /home/bbs)。這樣使用的好處是,利於調試和安裝;也利於安全。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.