天天看點

更改使用者 ID 和更改組 ID

UNIX 系統中的特權(如能改變目前日期的表示法)和通路控制(如能否讀、寫一個特定檔案)都是基于使用者 ID 群組 ID 的。當程式需要增加或降低特權,需要允許或阻止對某些資源的通路時,都需要更換自己的使用者 ID 或組 ID。

可以使用 setuid 函數設定實際使用者 ID 和有效使用者 ID,使用 setgid 函數設定實際組 ID 和有效組 ID。

更改使用者 ID 有若幹規則(這些規則也适用于組 ID)。

1、若程序具有超級使用者特權,則 setuid 會将實際使用者 ID、有效使用者 ID 及儲存的設定使用者 ID(saved set-user-ID)設定為 uid。

2、若程序沒有超級使用者特權,但是 uid 等于實際使用者 ID 或儲存的設定使用者 ID,則 setuid 隻将有效使用者 ID 設定為 uid。

3、如果上面兩個條件都不滿足,則将 errno 設定為 EPERM,并傳回 -1。

這裡假設 _POSIX_SAVED_IDS 為真,如果沒有提供這種功能,則上面所說的關于儲存的設定使用者 ID 部分都無效(在 POSIX.1 2001 版中,儲存的 ID 是強制性功能。而在早期版本中則是可選的。為了測試某實作是否支援該功能,應用程式可在編譯時測試常量 _POSIX_SAVED_IDS,或者在運作時以 _SC_SAVED_IDS 參數調用 sysconf 函數)。

關于核心所維護的這 3 個使用者 ID,還要注意以下幾點。

1、隻有超級使用者程序可以更改實際使用者 ID。通常,實際使用者 ID 是在登入時由 login(1) 程式設定的,而且決不會改變它。因為 login 是一個超級使用者程序,是以當它調用 setuid 時,會設定所有 3 個使用者 ID。

2、僅當對程式檔案設定了設定使用者 ID 位時,exec 函數才改變有效使用者 ID。任何時候都可以調用 setuid 将有效使用者 ID 設定為實際使用者 ID 或儲存的設定使用者 ID。

3、儲存的設定使用者 ID 位是由 exec 複制有效使用者 ID 而得到的。如果設定了檔案的設定使用者 ID 位,則在 exec 根據檔案的使用者 ID 設定了程序的有效使用者 ID 以後,這個副本就被儲存起來了。

下表總結了更改這 3 個使用者 ID 的不同方法。

[img]http://dl2.iteye.com/upload/attachment/0126/8928/911b0d28-0fbb-3352-8909-c79b12f8dc8a.png[/img]

注意,在[url=http://aisxyz.iteye.com/admin/blogs/2391275]程序辨別符操作函數[/url]中所述的 getuid 和 geteuid 函數隻能獲得實際使用者 ID 和有效使用者 ID 的目前值,并沒有可移植的方法去獲得儲存的設定使用者 ID 的目前值(FreeBSD 8.0 和 Linux 3.2.0 提供了 getresuid 和 getresgid 函數,它們可以分别用于擷取儲存的設定使用者 ID 和儲存的設定組 ID)。

曆史上,BSD 支援 setreuid 函數,可用于交換實際使用者 ID 和有效使用者 ID 的值。

如若其中任一參數的值為 -1,則表示相應的 ID 保持不變。

一個非特權使用者總能交換實際使用者 ID 和有效使用者 ID。這就允許一個設定使用者 ID 程式交換成使用者的普通權限,以後又可再次交換回設定使用者 ID 權限。POSIX.1 引進了儲存的設定使用者 ID 特性後,其規則也相應加強,它允許一個非特權使用者将其有效使用者 ID 設定為儲存的設定使用者 ID(4.3 BSD 沒有儲存的設定使用者 ID 特性,而是使用上面這兩個函數來代替。這就允許一個非特權使用者交換這兩個使用者 ID 的值。但當使用此特性的程式生成 shell 程序時,它應該在子程序調用 exec 前将子程序的實際使用者 ID 和有效使用者 ID 都設定成普通使用者 ID。否則當實際使用者 ID 具有特權時,shell 程序就可調用 setreuid 交換兩個使用者 ID 值以獲得更多權限)。

POSIX.1 包含了 seteuid 和 setegid 函數,它們類似于 setuid 和 setgid,但隻更改有效使用者 ID 和有效組 ID。

一個非特權使用者可将其有效使用者 ID 設定為其實際使用者 ID 或其儲存的設定使用者 ID,而一個特權使用者則可将有效使用者 ID 設定為 uid。

下圖描述了本文所述的更改 3 個不同使用者 ID 的各個函數。

[img]http://dl2.iteye.com/upload/attachment/0126/9009/0d6bb3a9-e865-3fcd-b295-f03bd5d6850f.png[/img]

為說明儲存的設定使用者 ID 特性的用法,下面就來觀察一個使用了該特性的 at(1)程式,它用于排程将來某個時刻要運作的指令(Linux 3.2.0 上的 at 程式的設定使用者 ID 是 daemon 使用者,FreeBSD 8.0、Mac OS X 10.6.8 以及 Solaris 10 上的 at 程式的設定使用者 ID 是 root 使用者。這允許 at 指令對守護程序擁有的特權檔案具有寫權限,守護程序代表使用者運作 at 指令。在 Linux 3.2.0 上,程式是用 atd(8)守護程序運作的,在 FreeBSD 8.0 和 Solaris 10 上是通過 cron 守護程序運作的,在 Max OS X 10.6.8 上是通過 launchd(8)守護程序運作的)。為了防止被欺騙而運作不被允許的指令或讀、寫沒有通路權限的檔案,at 程式和最終代表使用者運作指令的守護程序必須在使用者特權和守護程序特權之間切換。下面列出了工作步驟。

以這種方式使用儲存的設定使用者 ID,隻有在需要提升特權的時候,我們通過設定程式檔案的設定使用者 ID 而得到的額外權限。然而,其他時間程序在運作時隻具有普通權限。如果程序不能在其結束部分切換回儲存的設定使用者 ID,那麼就不得不在全部運作時間都保持額外的權限(這可能會造成麻煩)。

注意,上面針對使用者 ID 所說的規則也适用于各個組 ID,不過附屬組 ID 不受 setgid、setregid 和 setegid 函數的影響。

繼續閱讀