免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1384 | 回复: 0
打印 上一主题 下一主题

“实际用户ID”、“有效用户ID”和“保存的设置用户ID”三个术语的区别是什么? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-05-24 09:57 |只看该作者 |倒序浏览
《UNIX环境高级编程》这三个词很常见,以前一直没注意,哪位能用较生动形象的语言描述一下,谢谢了.

lonelyair
回复于:2006-08-31 11:17:50

顶一下,
我也想知道。

aple_smx
回复于:2006-08-31 11:49:00

还望高手指点,通过man得不到太多资讯

雨丝风片
回复于:2006-08-31 12:09:13

引用:Maurice J.Bach 的《The Design of The UNIX Operating System》一书中对这个问题的论述。。。
p227
7.6 THE USER ID OF A PROCESS
内核会给每个进程关联两个和进程ID无关的用户ID,一个是真实用户ID,还有一个是有效用户ID或者称为setuid(set user ID)。真实用户ID用于标识由谁为正在运行的进程负责。有效用户ID用于为新创建的文件分配所有权、检查文件访问许可,还用于通过kill系统调用向其它进程发送信号时的许可检查。内核允许一个进程以调用exec一个setuid程序或者显式执行setuid系统调用的方式改变它的有效用户ID。
所谓setuid程序是指一个设置了许可模式字段中的setuid bit的可执行文件。当一个进程exec一个setuid程序的时候,内核会把进程表以及u区中的有效用户ID设置成该文件所有者的ID。为了区分这两个字段,我们把进程表中的那个字段称作保存用户ID。可以通过一个例子来演示这两个字段的区别。
setuid系统调用的语法是 setuid(uid) ,其中,uid是新的用户ID,该系统调用的结果取决于有效用户ID的当前值。如果调用进程的有效用户ID是超级用户,内核会把进程表以及u区中的真实和有效用户ID都设置成uid。如果调用进程的有效用户ID不是超级用户,仅当uid等于真实用户ID或保存用户ID时,内核才会把u区中的有效用户ID设置成uid。否则,该系统调用将返回错误。一般来说,一个进程会在fork系统调用期间从父进程那儿继承它的真实和有效用户ID,这些数值即使经过exec系统调用也会保持不变。
存储在u区中的有效用户ID是最近一次setuid系统调用或是exec一个setuid程序的结果;只有它会被用于文件访问许可。进程表中的保存用户ID使得一个进程可以通过执行setuid系统调用把有效用户ID设置成它的值,以此来恢复最初的有效用户ID。
setuid程序的例子:login,mkdir。

引用:Uresh Vahalia 的《UNIX Internals:The New Frontiers》一书中对这个问题的论述。。。  
p27
2.3.3 User Credentials
UID和GID这样的标识符会影响文件的所有权和访问许可,以及向其它进程发送信号的能力。这些属性统称为凭证。
每个进程都有两对ID ——真实的和有效的。当一个用户登录的时候,login程序会把两对ID设置成密码数据库(/etc/passwd文件,或某些如Sun Microsystems的NIS之类的分布式机制)中指定的UID和GID。当一个进程fork的时候,子进程将从父进程那儿继承它的凭证。
有效UID和有效GID印象文件的创建和访问。在创建文件的时候,内核将文件的所有者属性设置成创建进程的有效UID和有效GID。在访问文件的时候,内核使用进程的有效UID和GID来判断它是否能够访问该文件。真实UID和真实GID标识进程的真实所有者,会影响到发送信号的权限。对于一个没有超级用户权限的进程来说,仅当它的真实或有效UID于另一个进程的真实UID匹配时它才能向那个进程发送信号。
有三个系统调用可以改变凭证。如果一个进程调用exec执行一个安装为suid模式的程序,内核将把进程的有效UID修改成文件的所有者。同样,如果该程序安装为sgid模式,内核则会去修改调用进程的有效GID。UNIX提供这个特性是想赋予用户特殊的权限以完成一些特定的任务。
一个用户还可以通过调用setuid或setgid来改变它的凭证。超级用户可以通过这些系统调用改变真实的和有效的UID以及GID。普通用户则只能通过这些调用来把它们的有效UID或GID改回到真实的数值。
System V和BSD UNIX在处理凭证方面存在着一些差别。SVR3还维护了一个saved UID和saved GID,分别是在调用exec之前的有效UID和GID的数值。setuid和setgid系统调用还可以把有效ID恢复为保存的数值。4.3BSD不支持这一特性,它允许一个用户属于一个辅组(supplemental group)的集合(使用setgroups系统调用)。用户创建的文件将属于它的主组(primary group),而用户则既可以访问属于主组的文件,也可以访问属于辅组的文件。
SVR4整合了上述所有特性。它支持附组,也会在exec的时候维护saved UID和GID。
setuid程序的例子:passwd。

引用:Marshall Kirk McKusick, George V. Neville-Neil 的《The Design and Implementation of the FreeBSD Operating System》一书中对这个问题的论述。。。  
3.7 User, Group, and Other Identifiers
每个FreeBSD进程的状态里都有一个UID和一组GID。一个进程的文件系统访问特权就是由它的UID和GIDs来定义的。通常,这些标识符都是新进程创建的时候从父进程那儿自动继承过来的。只有超级用户才能修改一个进程的真实UID或真实GID。这个方案在各种特权之间进行了严格的区分,确保除了超级用户之外的其它任何用户都无法获得特权。
每个文件都有三组许可bit,分别用于所有者、组以及其它用户的读、写或执行许可。这些许可bit将按如下顺序进行检查:
    1、如果文件的UID和进程的UID相同,则仅应用所有者的许可,不再检查组和其它用户的许可。
    2、如果UID不匹配,但文件的GID和进程的众多GID之一匹配,则仅引用组的许可,不再检查所有者和其它用户的许可。
    3、仅当进程UID和GID与文件的UID和GID都不匹配时,才会去检查其它用户的许可。如果这些许可不允许所请求的操作,该操作就会失败。
一个进程的UID和GIDs是从它的父进程那儿继承来的。当一个用户登录的时候,login程序会在执行exec系统调用运行用户的登录shell之前设置好UID和GIDs,因此,后续的所有进程都会继承到恰当的标识符。
我们经常会想赋予一个用户有限的额外特权。......为了解决这个问题,内核允许程序在运行过程中创建被赋予特权的程序。以不同的UID运行的程序被称为setuid程序,以一个额外的组特权运行的程序被称为setgid程序。当运行一个setuid程序的时候,进程的许可将被扩展以包括与程序相关联的UID的许可。该程序的UID就被称为进程的有效UID,而进程最初的UID则被称为真实UID。同样,执行一个setgid程序会把进程的许可扩展为程序的GID的许可,相应的也有有效GID和真实GID的定义。
系统可以通过setuid和setgid程序来提供对文件或服务的受控访问。当然,这样的程序必须仔细编写,以保证它们只具有一些有限的功能。
UID和GIDs是作为每个进程的状态的一部分来维护的。由于历史原因,GIDs被实现成了一个显著的GID(即有效GID)和一个GIDs的辅助数组,不过在逻辑上则被看作是一组GIDs。在FreeBSD中,那个显著的GID就是GIDs数组中的第一个条目。辅助数组的大小是固定的(FreeBSD中是16),不过可以通过重新编译内核来修改这个数值。
FreeBSD是通过把运行setgid程序的进程的辅组数组中的第0个元素设置成文件的属组来实现setgid功能的。之后就可以像普通进程那样对许可进行检查了。由于存在额外的组,setgid程序就能够比一个运行没有特殊权限的程序的用户进程访问更多的文件。为了避免在运行一个setgid程序的时候丢失与第0个数组元素中的组相关联的特权,login程序会在初始化用户的辅组数组的时候将第0个数组元素复制到第一个数组元素中。因此,当运行的setgid程序修改第0个元素的时候,用户不会丢失任何特权,因为曾经保存在第0个数组元素中的组仍然可以从第一个数组元素中得到。
setuid功能是通过把进程的有效UID从用户的数值修改为被运行的程序的数值来实现的。和setgid一样,保护机制此时将毫不变样地允许访问,同时也不会意识到程序正在运行setuid。由于一个进程在同一时刻只能有一个UID,在运行setuid的时候就可能会丢失某些特权。在加载新的有效UID的时候,之前的真实UID将会继续作为真实UID。不过真实UID是不会用于任何确认检查的。
一个setuid进程在运行过程中可能会想临时取消它的特殊权限。比如,它可能只在运行开始和结束的时候需要访问某个受限文件的特殊权限。在其余的运行时间中,它应当只具有真实用户的权限。在BSD的早期版本中,特权的回收是通过对真实的和有效的UID进行切换来完成的。由于只有有效UID被用于访问控制,这个方法既提供了所需的语义,又提供了一个隐藏特殊权限的地方。这个方法的缺点是很容易就混淆了真实的和有效的UID。
在FreeBSD中,使用了一个额外的标识符,即saved UID来记录setuid程序的身份。当一个程序被exec之后,它的有效UID会被拷贝到saved UID中。下表中的第1行表示了一个没有特权的程序,它的真实、有效以及saved UID都是真实用户的数值。第2行正在运行中的setuid程序,它的有效UID被设置成了具有相应特权的UID,而这个特权UID也会被拷贝到saved UID中。
Actions affecting the real, effective, and saved UIDs.
_________________________________________________________________
Action            Real    Effective    Saved
1.exec-normal     R       R            R
2.exec-setuid     R       S            S
3.seteuid(R)      R       R            S
4.seteuid(S)      R       S            S
5.seteuid(R)      R       R            S
6.exec-normal     R       R            R
Key:R-real user identifier; S-special-privilege user identifier
_________________________________________________________________
seteuid系统调用只会修改有效UID,而不会影响真实的或saved UID。seteuid系统调用被允许将有效UID修改为真实的或saved UID的数值。表中的第3行和第4行表示了一个setuid程序在一直保持正确的真实UID的同时是如何放弃和重新取回它的特殊权限的。第5行和第6行表示了一个setuid程序可以运行一个子进程而不赋予它特殊权限。首先,它会把它的有效UID设置成真实UID。然后,当exec那个子进程的时候,有效UID就会被拷贝到saved UID中,从此就会失去对特权UID的所有访问。
与此类似,也有一个saved GID机制,允许进程在真实GID和最初的有效GID之间进行切换。

引用:IEEE Std 1003.1™, 2004 Edition
Standard for Information Technology —
Portable Operating System Interface (POSIX)
System Interfaces   中对setuid()的论述。。。
NAME
    setuid—set user ID
SYNOPSIS
    #include  
    int setuid(uid_t uid);
DESCRIPTION
    If the process has appropriate privileges, setuid( ) shall set the real user ID,  
    effective user ID, and the saved set-user-ID of the calling process to uid.
    If the process does not have appropriate privileges, but uid is equal to the real user
    ID or the saved set-user-ID, setuid( ) shall set the effective user ID to uid; the real
    user ID and saved set-user-ID shall remain unchanged.
    The setuid( ) function shall not affect the supplementary group list in any way.
RETURN VALUE
    Upon successful completion, 0 shall be returned. Otherwise, ?1 shall be returned and
    errno set to indicate the error.
ERRORS
    The setuid( ) function shall fail, return ?1, and set errno to the corresponding value
    if one or more of the following are true:
    [EINVAL]    The value of the uid argument is invalid and not supported by the
                implementation.
    [EPERM]     The process does not have appropriate privileges and uid does not match the
                real user ID or the saved set-user-ID.
EXAMPLES
    None.
APPLICATION USAGE
    None.
RATIONALE
    The various behaviors of the setuid( ) and setgid( ) functions when called by  
    non-privileged processes reflect the behavior of different historical implementations.  
    For portability, it is recommended that new non-privileged applications use the  
    seteuid( ) and setegid( ) functions instead.
    The saved set-user-ID capability allows a program to regain the effective user ID  
    established at the last exec call. Similarly, the saved set-group-ID capability allows  
    a program to regain the effective group ID established at the last exec call.  
    These capabilities are derived from System V. Without them, a program might have to run
    as superuser in order to perform the same functions, because superuser can write on the
    user’s files. This is a problem because such a program can write on any user’s files,
    and so must be carefully written to emulate the permissions of the calling process  
    properly. In System V, these capabilities have traditionally been implemented only via
    the setuid( ) and setgid( ) functions for non-privileged processes. The fact that the  
    behavior of those functions was different for privileged processes made them difficult  
    to use. The POSIX.1-1990 standard defined the setuid( ) function to behave differently
    for privileged and unprivileged users. When the caller had the appropriate privilege,  
    the function set the calling process’ real user ID, effective user ID, and saved  
    set-user ID on implementations that supported it. When the caller did not have the  
    appropriate privilege, the function set only the effective user ID, subject to  
    permission checks. The former use is generally needed for utilities like login and su,  
    which are not conforming applications and thus outside the scope of IEEE Std  
    1003.1-2001. These utilities wish to change the user ID irrevocably to a new value,  
    generally that of an unprivileged user. The latter use is needed for conforming  
    applications that are installed with the set-user-ID bit and need to perform operations
    using the real user ID.
    IEEE Std 1003.1-2001 augments the latter functionality with a mandatory feature named
    _POSIX_SAVED_IDS. This feature permits a set-user-ID application to switch its  
    effective user ID back and forth between the values of its exec-time real user ID and  
    effective user ID. Unfortunately, the POSIX.1-1990 standard did not permit a conforming  
    application using this feature to work properly when it happened to be executed with  
    the (implementation-defined) appropriate privilege. Furthermore, the application did  
    not even have a means to tell whether it had this privilege. Since the saved  
    set-user-ID feature is quite desirable for applications, as evidenced by the fact that  
    NIST required it in FIPS 151-2, it has been mandated by IEEE Std 1003.1-2001. However,  
    there are implementors who have been reluctant to support it given the limitation  
    described above.
    The 4.3BSD system handles the problem by supporting separate functions: setuid( )  
    (which always sets both the real and effective user IDs, like setuid( ) in IEEE Std  
    1003.1-2001 for privileged users), and seteuid( ) (which always sets just the effective
    user ID, like setuid( ) in IEEE Std 1003.1-2001 for non-privileged users). This  
    separation of functionality into distinct functions seems desirable. 4.3BSD does not  
    support the saved set-user-ID feature. It supports similar functionality of switching  
    the effective user ID back and forth via setreuid( ), which permits reversing the real  
    and effective user IDs. This model seems less desirable than the saved set-user-ID  
    because the real user ID changes as a side effect. The current 4.4BSD includes saved
    effective IDs and uses them for seteuid( ) and setegid( ) as described above. The  
    setreuid( ) and setregid( ) functions will be deprecated or removed.
    The solution here is:
      . Require that all implementations support the functionality of the saved  
        set-user-ID, which is set by the exec functions and by privileged calls to  
        setuid( ).
      . Add the seteuid( ) and setegid( ) functions as portable alternatives to setuid( )  
        and setgid( ) for non-privileged and privileged processes.
    Historical systems have provided two mechanisms for a set-user-ID process to change its
    effective user ID to be the same as its real user ID in such a way that it could return
    to the original effective user ID: the use of the setuid( ) function in the presence of
    a saved set-user-ID, or the use of the BSD setreuid( ) function, which was able to swap
    the real and effective user IDs. The changes included in IEEE Std 1003.1-2001 provide a
    new mechanism using seteuid( ) in conjunction with a saved set-user-ID. Thus, all  
    implementations with the new seteuid( ) mechanism will have a saved set-user-ID for  
    each process, and most of the behavior controlled by _POSIX_SAVED_IDS has been changed  
    to agree with the case where the option was defined. The kill ( ) function is an  
    exception. Implementors of the new seteuid( ) mechanism will generally be required to  
    maintain compatibility with the older mechanisms previously supported by their systems.  
    However, compatibility with this use of setreuid( ) and with the _POSIX_SAVED_IDS
    behavior of kill ( ) is unfortunately complicated. If an implementation with a saved  
    set-user-ID allows a process to use setreuid( ) to swap its real and effective user  
    IDs, but were to leave the saved set-user-ID unmodified, the process would then have an
    effective user ID equal to the original real user ID, and both real and saved  
    set-user-ID would be equal to the original effective user ID. In that state, the real  
    user would be unable to kill the process, even though the effective user ID of the  
    process matches that of the real user, if the kill ( ) behavior of _POSIX_SAVED_IDS
    was used. This is obviously not acceptable. The alternative choice, which is used in  
    at least one implementation, is to change the saved set-user-ID to the effective user  
    ID during most calls to setreuid( ). The standard developers considered that  
    alternative to be less correct than the retention of the old behavior of kill ( ) in  
    such systems. Current conforming applications shall accommodate either behavior from  
    kill ( ), and there appears to be no strong reason for kill( ) to check the saved  
    set-user-ID rather than the effective user ID.
FUTUREDIRECTIONS
    None.
SEE ALSO
    exec, getegid( ), geteuid( ), getgid( ), getuid( ), setegid( ), seteuid( ), setgid( ),  
    setregid( ), setreuid( ), the Base Definitions volume of IEEE Std 1003.1-2001,  
    ,  
CHANGE HISTORY
    First released in Issue 1. Derived from Issue 1 of the SVID.
Issue 6
    In the SYNOPSIS, the optional include of the header is removed.
    The following new requirements on POSIX implementations derive from alignment with the
    Single UNIX Specification:
      . The requirement to include has been removed. Although  
        was required for conforming implementations of previous POSIX specifications, it  
        was not required for UNIX applications.
      . The functionality associated with _POSIX_SAVED_IDS is now mandatory. This is a FIPS
        requirement.
    The following changes were made to align with the IEEE P1003.1a draft standard:
      . The effects of setuid( ) in processes without appropriate privileges are changed.
      . A requirement that the supplementary group list is not affected is added.


flw
回复于:2006-08-31 13:56:16

一个进程的 real user ID 是指运行此进程的用户角色的 ID。
一个进程的 effective user ID 是指此进程目前实际有效的用户 ID(也就是权限的大小),effective user ID 主要用来校验权限时使用,比如打开文件、创建文件、修改文件、kill 别的进程,等等。
如果一个进程是以 root 身份来运行的,那么上面这两个 ID 可以用 setuid/seteuid 随便修改,想怎么改就怎么改,改来改去都可以。
但是如果一个进程是以普通用户身份来运行的,那么上面这两个 ID 一般来说是相同的,并且也不能随便修改。只有一种情况例外:此进程的可执行文件的权限标记中,设置了“设置用户 ID”位!
在命令行中,设置一个可执行文件的“设置用户 ID”位的最简单的方法,就是用
chmod +s /path/to/file
这个命令。
一旦用了这个命令之后,再执行这个文件,
那么生成的进程的 effective user ID 就变成了这个可执行文件的 owner user ID(属主用户 ID),
而 real user ID 仍然是启动这个程序时所用的用户的 ID。
打个比方来说,如果有这样的一个文件:
引用:-rwsr-sr-x 1 susesuse susesuse 7902 2006-08-31 13:22 tuid
注意这个文件已经用 chmod +s 命令设置过“设置用户 ID”位了。
然后我用 flw 这个用户来执行它,那么生成的进程它的 real user ID 就是 flw(因为我是用 flw 运行的),但是 effective user ID 就变成了 susesuse(因为这个可执行文件被设置了“设置用户 ID”位,并且它的 owner user ID 是 susesuse)。
这时,这个进程实际上就有两个用户权限了。只不过目前生效的是 susesuse,因此它目前能够且只能够操作 susesuse 用户的文件,如果现在我又想要操作 flw 用户的文件怎么办?
很简单,只需要 seteuid( getuid() ) 就可以了。执行完这句之后,effective user ID 就变成和 real user ID 一样了,都变成 flw 了。
可是如果过了一会儿我又想要变回来怎么办?因为 effective user ID 和 real user ID 此时都变成了 flw 了,所以操作系统必须得有一个地方保存住原来的“设置用户 ID”(也就是可执行文件的 owner user ID),不然等你再想要 seteuid 的时候,操作系统就不知道你有没有那个权利了。(总不能再去访问一次文件系统吧?那样也太没有效率了)
操作系统为了能够在设置了 seteuid 之后,再次设置回来,所以特地将原来的“设置用户 ID”保存下来了,这个保存下来的设置用户 ID 自然就叫做“保存的设置用户 ID”。
下面看一段我写的例子程序:
flw@Sleeper:~$ whoami
flw
flw@Sleeper:~$ cat tuid.c
# include
# include
# include
int main( void )
{
    struct passwd *pwd;
    pwd = getpwuid( geteuid() );
    printf( "effective UID: [%s]\n", pwd->pw_name );
    system( "touch /tmp/foo.txt; ls -l /tmp/foo.txt; rm -rf /tmp/foo.txt" );
    printf( "\nset EUID to `flw'..\n" );
    pwd = getpwnam( "flw" );
    seteuid(pwd->pw_uid);
    pwd = getpwuid( geteuid() );
    printf( "effective UID: [%s]\n", pwd->pw_name );
    system( "touch /tmp/foo.txt; ls -l /tmp/foo.txt; rm -rf /tmp/foo.txt" );
    printf( "\nset EUID to `root'..\n" );
    seteuid(0);
    pwd = getpwuid( geteuid() );
    printf( "effective UID: [%s]\n", pwd->pw_name );
    system( "touch /tmp/foo.txt; ls -l /tmp/foo.txt; rm -rf /tmp/foo.txt" );
    return 0;
}
flw@Sleeper:~$ su root -c "cc -o tuid tuid.c; chmod +s tuid; ls -al tuid"
Password:
-rwsr-sr-x 1 root root 7902 2006-08-31 13:55 tuid
flw@Sleeper:~$ ./tuid
effective UID: [root]
-rw-r--r-- 1 root root 0 2006-08-31 13:55 /tmp/foo.txt
set EUID to `flw'..
effective UID: [flw]
-rw-r--r-- 1 flw root 0 2006-08-31 13:55 /tmp/foo.txt
set EUID to `root'..
effective UID: [root]
-rw-r--r-- 1 root root 0 2006-08-31 13:55 /tmp/foo.txt
flw@Sleeper:~$

aple_smx
回复于:2006-08-31 15:23:26

well

yulc
回复于:2006-08-31 15:41:47

引用:
注意这个文件已经用 chmod +s 命令设置过“设置用户 ID”位了。
然后我用 flw 这个用户来执行它,那么生成的进程它的 real user ID 就是 flw(因为我是用 flw 运行的),但是 effective user ID 就变成了 susesuse(因为这个可执行文件被设置了“设置用户 ID”位,并且它的 owner user ID 是 susesuse)。
这时,这个进程实际上就有两个用户权限了。只不过目前生效的是 susesuse,因此它目前能够且只能够操作 susesuse 用户的文件,如果现在我又想要操作 flw 用户的文件怎么办?

flw, 你说的与我的程序表现似乎不一样.
当你用flw来执行这个程序时,虽然effective id 改为了susesuse,但是在程序中必须执行了 setuid() 以后, 才会具有susesuse 的权限的. 而不是一执行就会有这个权限.
  我的程序如下, /home/yulc 目录是 700, 我编译这个程序如这个样子:
-rwsr-sr-x 1  yulc  yulc  5230  Aug  31  15:36    test
#include
#include
#include
#include
main()
{
        pid_t pid;
        pid = getuid();
        printf("getuid:%d\n", pid);
        pid = geteuid();
        printf("geteuid:%d\n", pid);
        // setuid(500); // 500 是 yulc uid.
        // seteuid(0);
        system("ls -l /home/yulc");
}
但如果我使用其它用户身份来执行这个程序, 会无法列出目录, 除非放开setuid(500)那句话.

yulc
回复于:2006-08-31 15:48:38

我新建了一个用户test, uid是501, 当我用test执行上面的程序,结果如下:
getuid:501
geteuid:500
ls: /home/yulc: Permission denied

yulc
回复于:2006-08-31 15:58:11

我的平台, 表现与你不一样呀. flw
我是 fc5:
[yulc@localhost tmp]$ whoami
yulc
[yulc@localhost tmp]$ ll tuid
-rwsr-sr-x 1 root root 5580 Aug 31 15:57 tuid
[yulc@localhost tmp]$ cat tuid.c
# include
# include
# include
int main( void )
{
    struct passwd *pwd;
    pwd = getpwuid( geteuid() );
    printf( "effective UID: [%s]\n", pwd->pw_name );
    system( "touch /tmp/foo.txt; ls -l /tmp/foo.txt; rm -rf /tmp/foo.txt" );
    printf( "\nset EUID to `yulc'..\n" );
    pwd = getpwnam( "yulc" );
    seteuid(pwd->pw_uid);
    pwd = getpwuid( geteuid() );
    printf( "effective UID: [%s]\n", pwd->pw_name );
    system( "touch /tmp/foo.txt; ls -l /tmp/foo.txt; rm -rf /tmp/foo.txt" );
    printf( "\nset EUID to `root'..\n" );
    seteuid(0);
    pwd = getpwuid( geteuid() );
    printf( "effective UID: [%s]\n", pwd->pw_name );
    system( "touch /tmp/foo.txt; ls -l /tmp/foo.txt; rm -rf /tmp/foo.txt" );
    return 0;
}
[yulc@localhost tmp]$ ./tuid
effective UID: [root]
-rw-rw-r-- 1 yulc yulc 0 Aug 31 15:58 /tmp/foo.txt
set EUID to `yulc'..
effective UID: [yulc]
-rw-rw-r-- 1 yulc yulc 0 Aug 31 15:58 /tmp/foo.txt
set EUID to `root'..
effective UID: [root]
-rw-rw-r-- 1 yulc yulc 0 Aug 31 15:58 /tmp/foo.txt

sway2004009
回复于:2006-08-31 16:07:39

个人觉得可能是bash版本的问题。
如果直接fopen创建文件的话,就没有问题。

yulc
回复于:2006-08-31 16:12:40

我晕, 确实是这样...
难怪我总是对seteuid() 晕晕的...
每次试验总是怪怪的..  
原来又漏掉了这一块知识....
谢谢.

susesuse
回复于:2006-08-31 19:30:19

受教了,多谢flw的耐心讲解和另一位版主提供的资料!

flw
回复于:2006-08-31 23:09:27

引用:原帖由 yulc 于 2006-8-31 16:12 发表
我晕, 确实是这样...
难怪我总是对seteuid() 晕晕的...
每次试验总是怪怪的..  
原来又漏掉了这一块知识....
谢谢.

我不清楚你是如何试验的,但是我坚信,不会和 bash 的版本有关。

yulc
回复于:2006-09-01 09:41:14

引用:原帖由 flw 于 2006-8-31 23:09 发表
我不清楚你是如何试验的,但是我坚信,不会和 bash 的版本有关。

flw, 首先, 我把你的源代码在我的FC5上执行, 是表面得不一致的.
用system 调用touch创建的文件并非像你说的那样,所以我用fopen创建的文件.
如下:
[test@localhost tmp]$ ls foo.txt
ls: foo.txt: No such file or directory
[test@localhost tmp]$ whoami
test
[test@localhost tmp]$ ll tuid
-rwsr-sr-x 1 root root 5324 Sep  1 09:38 tuid
[test@localhost tmp]$ ./tuid
effective UID: [root]
-rw-rw-r-- 1 root root 0 Sep  1 09:39 /tmp/foo.txt
rm: cannot remove `/tmp/foo.txt': Operation not permitted
[test@localhost tmp]$ cat tuid.c
# include
# include
# include
int main( void )
{
    struct passwd *pwd;
    pwd = getpwuid( geteuid() );
    printf( "effective UID: [%s]\n", pwd->pw_name );
    FILE *fp = fopen("/tmp/foo.txt","wb");
    fclose(fp);
    system( "ls -l /tmp/foo.txt; rm -rf /tmp/foo.txt" );
    return 0;
}
以上是fopen的版本, system调用touch版本如下:
[test@localhost tmp]$ ls foo.txt
ls: foo.txt: No such file or directory
[test@localhost tmp]$ whoami
test
[test@localhost tmp]$ ll tuid2
-rwsr-sr-x 1 root root 5581 Sep  1 09:48 tuid2
[test@localhost tmp]$ ./tuid2
effective UID: [root]
-rw-rw-r-- 1 test test 0 Sep  1 09:50 /tmp/foo.txt
[test@localhost tmp]$ cat tuid2.c
# include
# include
# include
int main( void )
{
    struct passwd *pwd;
    pwd = getpwuid( geteuid() );
    printf( "effective UID: [%s]\n", pwd->pw_name );
    system( "touch /tmp/foo.txt; ls -l /tmp/foo.txt; rm -rf /tmp/foo.txt" );
    return 0;
}
fopen是
effective UID: [root]
-rw-rw-r-- 1 root root 0 Sep  1 09:39 /tmp/foo.txt
而system 调用touch是
effective UID: [root]
-rw-rw-r-- 1 test test 0 Aug 31 15:58 /tmp/foo.txt
[ 本帖最后由 yulc 于 2006-9-1 09:52 编辑 ]

flw
回复于:2006-09-01 10:31:10

fopen 的结果肯定是对的,
我之所以用 system 也是图个方便,
那应该是我这边有问题了。
我再找找原因,一会儿回复。

flw
回复于:2006-09-01 10:46:06

搞不好就和那个破 SELinux 有关系。

柳五随风
回复于:2006-09-01 10:52:50

uid,就是我login的时候给我发的户口(确切的说是create a new account的时候就给了)
euid就是我进一个新的地方后给发的新证明身份的东西.比如本地人还用户口,外地人用"站主证".
suid,就是户口主人把它的户口让你临时用用(比如装个电话啥的,没有本地户口不给你办).

flw
回复于:2006-09-01 11:09:51

查出原因来了,
应该和 bash 的版本无关,但是和 bash 的环境有关,我用的是 Debian,你用的是 FC,两个发行版的配置环境不同,
影响了 bash  的行为。
[cdoe]flw@Sleeper:~$ man bash 2>/dev/null | head -205 | tail -7
       If the shell is started with the effective user (group) id not equal to
       the real user (group) id, and the -p option is not supplied, no startup
       files are read, shell functions are not inherited from the environment,
       the  SHELLOPTS  variable, if it appears in the environment, is ignored,
       and the effective user id is set to the real user id.  If the -p option
       is  supplied  at  invocation, the startup behavior is the same, but the
       effective user id is not reset.
flw@Sleeper:~$

flw
回复于:2006-09-01 11:12:57

晕~
Debian 也脱不了干系。
引用:       Do  not  use  system()  from a program with set-user-ID or set-group-ID
       privileges, because strange values for some environment variables might
       be  used  to subvert system integrity.  Use the exec(3) family of func-
       tions instead, but not execlp(3) or execvp(3).  system() will  not,  in
       fact,  work  properly  from  programs  with set-user-ID or set-group-ID
       privileges on systems on which /bin/sh is bash version 2, since bash  2
       drops  privileges  on startup.  (Debian uses a modified bash which does
       not do this when invoked as sh.
)


flw
回复于:2006-09-01 11:24:40

找到了。
http://ftp.debian.org/debian/pool/main/b/bash/bash_3.1-5.diff.gz
第 532 行,Debian 增加了一个限制条件。
524 +diff -urb bash.orig/shell.c bash/shell.c
525 +--- bash.orig/shell.c        2003-06-03 19:50:35.000000000 +0200
526 ++++ bash/shell.c        2003-09-28 00:26:28.000000000 +0200
527 +@@ -447,7 +447,7 @@
528 +   if (dump_translatable_strings)
529 +     read_but_dont_execute = 1;
530 +
531 +-  if (running_setuid && privileged_mode == 0)
532 ++  if (running_setuid && privileged_mode == 0 && act_like_sh == 0)
533 +     disable_priv_mode ();
534 +
535 +   /*

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/31125/showart_308377.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP