Linux 安全编程(一) 之 SUID 和 SGID

原文地址:http://blog.csdn.net/xuyunzhang/article/details/7814340

 

此文参考连接 http://forum.ubuntu.org.cn/weblog_entry.php?e=6900 且加上本人实际验证例子改编而成。

由于用户在UNIX下经常会遇到SUID、SGID的概念,而且SUID和SGID涉及到系统安全,所以用户也比较关心这个问题。

一、UNIX下关于文件权限的表示方法和解析

SUID 是 Set User ID, SGID 是 Set Group ID的意思。
UNIX下可以用ls -l命令来看到文件的权限。用ls命令所得到的表示法的格式是类似这样的:-rwxr-xr-x。
下面解析一下格式所表示的意思。
这种表示方法一共有十位: 9 8 7 6 5 4 3 2 1 0 - r w x r - x r - x

第9位表示文件类型,可以为p、d、l、s、c、b和-:
p表示命名管道文件;
d表示目录文件;
l表示符号连接文件;
-表示普通文件;
s表示socket文件;
c表示字符设备文件;
b表示块设备文件;

第8-6位、5-3位、2-0位分别表示文件所有者的权限,同组用户的权限,其他用户或组的权限,其形式为rwx:
r表示可读,可以读出文件的内容;
w表示可写,可以修改文件的内容;
x表示可执行,可运行这个程序;
没有权限的位置用-表示。
例子:

[cpp] view plain copy print ?
  1. # ls -l /dev  
  2. crw-rw-r--    1 admin123 root      45, 255 Jul 29 01:42 isdninfo  
  3. crw-rw-r--    1 admin123 root       1,   2 Jul 29 01:42 kmem  
  4. lrwxrwxrwx    1 admin123 root           12 Jul 29 01:42 log -> /var/log/log  
  5. crw-rw-r--    1 admin123 root       1,   1 Jul 29 01:42 mem  
  6. brw-rw-r--    1 admin123 root      31,   0 Jul 29 01:42 mtdblock0  
  7. brw-rw-r--    1 admin123 root      31,   1 Jul 29 01:42 mtdblock1  
  8. #  
  9. # ls -l /var  
  10. srwxr-xr-x    1 admin123 root            0 Jul 29 22:30 rtpproxy.sock  
  11. drwxr-xr-x    2 admin123 root            0 Jul 29 22:30 run  
  12. -rw-r--r--    1 admin123 root            2 Jul 29 22:30 runhttpd  
  13. drwxr-xr-x    4 admin123 root            0 Jan  1  2011 samba  
  14. -rw-------    1 admin123 root         8192 Jan  1  2011 secrets.tdb  
  15. drwxr-x---    3 admin123 root            0 Jul 30 02:13 ser  
  16. prw-rw----    1 admin123 root            0 Jul 30 03:19 ser_fifo  



 

[cpp] view plain copy print ?
  1. [quagga@localhost socket]$ ls -l openfile.c  
  2. -rw-rw---- 1 zhang zhang  1770 2012-07-29 21:15 openfile.c  
  3. [zhang@localhost ctest]$ ls -l | grep socket  
  4. drwxr-xrwx  3 zhang zhang     4096 2012-07-31 10:13 socket  


表示文件socket是目录文件,文件的所有者是zhang用户,而zhang用户属于zhang组,
文件只有1个硬连接,长度是4096个字节,最后修改时间2012-07-315。所有者zhang对文件有读写执行权限,
zhang组的成员对文件有读和执行权限, 其他的用户对这个文件读写执行权限。

如果一个文件被设置了SUID或SGID位,会分别表现在所有者或同组用户的权限的可执行位上。
例如:
1、-rwsr-xr-x 表示SUID和所有者权限中可执行位被设置
2、-rwSr--r-- 表示SUID被设置,但所有者权限中可执行位没有被设置
3、-rwxr-sr-x 表示SGID和同组用户权限中可执行位被设置
4、-rw-r-Sr-- 表示SGID被设置,但同组用户权限中可执行位没有被社置。

其实在UNIX的实现中,文件权限用12个二进制位表示,如果该位置上的值是1
表示有相应的权限: 11 10 9 8 7 6 5 4 3 2 1 0 S G T r w x r w x r w x
第11位为SUID位,第10位为SGID位,第9位为sticky位,第8-0位对应于上面三组rwx位。
11 10 9 8 7 6 5 4 3 2 1 0 上面的
-rwsr-xr-x的值为: 1 0 0 1 1 1 1 0 1 1 0 1
-rw-r-Sr--的值为: 0 1 0 1 1 0 1 0 0 1 0 0

给文件加SUID和SGID的命令如下:
chmod u+s filename 设置SUID位;
chmod u-s filename 去掉SUID设置;
chmod g+s filename 设置SGID位;
chmod g-s filename 去掉SGID设置;
另外一种方法是chmod命令用八进制表示方法的设置。如果明白了前面的12位 权限表示法也很简单。


二、SUID和SGID的详细解析

由于SUID和SGID是在执行程序(程序的可执行位被设置)时起作用,而可执行位只对普通文件和目录文件有意义,
所以设置其他种类文件的SUID和SGID位是没有多大意义的。首先讲普通文件的SUID和SGID的作用。
例子:

[cpp] view plain copy print ?
  1. [quagga@localhost socket]$ ls -l mycat  
  2. -rwxrwxr-x 1 zhang zhang 7421 2012-07-29 21:16 mycat  
  3. [quagga@localhost socket]$  
  4. [quagga@localhost socket]$ ls -l openfile.c  
  5. -rw-rw---- 1 zhang zhang  1770 2012-07-29 21:15 openfile.c  


显然普通文件mycat和openfile.c是属于用户zhang的,任何用户都可以执行这个mycat程序,
quagga没有读openfile.c的权限(只有用户zhang以及zhang的同组成员有读openfile.c的权限)。

UNIX的内核是根据什么来确定一个进程对资源的访问权限的呢?

是这个进程的运行用户的(有效)ID,包括user id和group id。
用户可以用id命令来查到自己的或其他用户的user id和group id。

[cpp] view plain copy print ?
  1. [quagga@localhost socket]$ id root  
  2. uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)  
  3. [quagga@localhost socket]$  
  4. [quagga@localhost socket]$ id zhang  
  5. uid=500(zhang) gid=500(zhang) groups=500(zhang)  
  6. [quagga@localhost socket]$  
  7. [quagga@localhost socket]$ id quagga  
  8. uid=501(quagga) gid=501(quagga) groups=501(quagga)  
  9. [quagga@localhost socket]$   


除了一般的user id 和group id外,还有两个称之为effective的id,就是有效id,
上面的四个id表示为:uid,gid,euid,egid。

内核主要是根据euid和egid来确定进程对资源的访问权限。
一个进程如果没有SUID或SGID位,则euid=uid egid=gid,分别是运行这个程序的用户的uid和gid。

[cpp] view plain copy print ?
  1. [quagga@localhost socket]$ ls -l openfile.c  
  2. -rw-rw---- 1 zhang zhang  1770 2012-07-29 21:15 openfile.c  
  3. [quagga@localhost socket]$  
  4. [quagga@localhost socket]$ ls -l mycat  
  5. -rwxrwxr-x 1 zhang zhang 7421 2012-07-29 21:16 mycat  
  6. [quagga@localhost socket]$  
  7. [quagga@localhost socket]$ which cat  
  8. /bin/cat  
  9. [quagga@localhost socket]$ ls -l /bin/cat  
  10. -rwxr-xr-x 1 root root  55184 2009-03-02 21:57 cat  
  11. [quagga@localhost socket]$  
  12. [quagga@localhost socket]$ cat openfile.c  
  13. cat: openfile.c: Permission denied  
  14. [quagga@localhost socket]$  
  15. [quagga@localhost socket]$ ./mycat openfile.c  
  16. cannot open openfile.c[quagga@localhost socket]$   


用户quagga的uid和gid分别为501和501,用户zhang的uid和gid为500和500,
由于mycat/cat程序没有设置SUID或SGID位,quagga运行mycat程序形成的进程的euid=uid=501,egid=gid=501,
内核根据这些值来判断进程对资源访问的限制,其实就是用户quagga对资源访问的权限,和zhang没关系。
(quagga对openfile.c没有读权限, 所以 mycat/cat程序去读openfile.c时会cannot open openfile.c/openfile.c: Permission denied,
尽管用户zhang以及zhang的同组成员有这个权限)

如果一个程序设置了SUID("chmod u+s mycat"),则euid和egid变成被运行的程序的所有者(zhang)的uid和gid,
例如quagga用户运行mycat,euid=500,egid=500,uid=501,gid=501,

[cpp] view plain copy print ?
  1. [zhang@localhost socket]$ ls -l openfile.c  
  2. -rw-rw---- 1 zhang zhang 1770 2012-07-29 21:15 openfile.c  
  3. [zhang@localhost socket]$  
  4. [zhang@localhost socket]$ ls -l mycat  
  5. -rwxrwxr-x 1 zhang zhang 7421 2012-07-29 21:16 mycat  
  6. [zhang@localhost socket]$  
  7. [zhang@localhost socket]$ chmod u+s mycat  
  8. [zhang@localhost socket]$  
  9. [zhang@localhost socket]$ ls -l mycat  
  10. -rwsrwxr-x 1 zhang zhang 7421 2012-07-29 21:16 mycat  
  11. [zhang@localhost socket]$   


则用户quagga运行这个进程,quagga具就具有它的属主zhang(uid=500)的资源访问权限(读openfile.c的权限)。

[quagga@localhost socket]$ ./mycat openfile.c

[cpp] view plain copy print ?
  1. [openfile.c-43]: sockfd[1]=4, fd=3  
  2. [my_open-78]: sockfd[0]=3, sockfd[1]=4, fd=4, c=x  
  3. /* 
  4. * this program is excuted by program of "mycat", 
  5. * execl("./openfile", "openfile", argsockfd, pathname, argmode, (char *) NULL); 
  6. * 
  7. */  
  8.   
  9. #include <stdio.h>  
  10. #include <unistd.h>  
  11. #include <stdlib.h>  
  12. #include <errno.h>  
  13. #include <sys/types.h>  
  14. #include <sys/socket.h>  
  15.   
  16. ssize_t write_fd(int fd, void *ptr, size_t nbytes, int sendfd);  
  17.   
  18. int main(int argc, char **argv)  
  19. {  
  20.     int fd = -1, n = 0;  
  21.     char buf[10240] = {0};  
  22.       
  23.     if (argc != 4)  
  24.     {  
  25.         fprintf(stderr, "openfile <sockfd#> <filename> <mode>\n");  
  26.         exit(255);  
  27.     }  
  28.   
  29.     if ( (fd = open(argv[2], atoi(argv[3]))) < 0 )  
  30.     {  
  31.         exit( (errno > 0) ? errno : 255 );  
  32.     }  
  33.   
  34.     /* 
  35.     n = read(fd, buf, sizeof(buf)); 
  36.     write(STDOUT_FILENO, buf, n); 
  37.     */  
  38.       
  39.     if ( write_fd(atoi(argv[1]), "x", 1, fd) < 0 )  
  40.     // if ( write(atoi(argv[1]), &fd, sizeof(int)) < 0 )  
  41.     {  
  42.         exit( (errno > 0) ? errno : 255 );  
  43.     }  
  44.       
  45.     fprintf(stderr, "[%s-%d]: sockfd[1]=%d, fd=%d\n", __FILE__, __LINE__, atoi(argv[1]), fd );  
  46.       
  47.     exit(0);  
  48. }  
  49.   
  50. ssize_t write_fd(int fd, void *ptr, size_t nbytes, int sendfd)  
  51. {  
  52.     struct msghdr msg;  
  53.     struct iovec    iov[1];  
  54.   
  55. #if 1  
  56.     union  
  57.     {  
  58.         struct cmsghdr cm;  
  59.         char control[CMSG_SPACE(sizeof(int))];  
  60.     } control_un;  
  61.       
  62.     struct cmsghdr *cmptr;  
  63.   
  64.     msg.msg_control = control_un.control;  
  65.     msg.msg_controllen = sizeof(control_un.control);  
  66.   
  67.     cmptr = CMSG_FIRSTHDR(&msg);  
  68.     cmptr->cmsg_len = CMSG_LEN(sizeof(int));  
  69.     cmptr->cmsg_level = SOL_SOCKET;  
  70.     cmptr->cmsg_type = SCM_RIGHTS;  
  71.     *((int *) CMSG_DATA(cmptr)) = sendfd;  
  72. #else  
  73.     msg.msg_accrights = (caddr_t) &sendfd;  
  74.     msg.msg_accrightslen = sizeof(int);  
  75. #endif  
  76.   
  77.     msg.msg_name = NULL;  
  78.     msg.msg_namelen = 0;  
  79.   
  80.     iov[0].iov_base = ptr;  
  81.     iov[0].iov_len = nbytes;  
  82.     msg.msg_iov = iov;  
  83.     msg.msg_iovlen = 1;  
  84.   
  85.     return(sendmsg(fd, &msg, 0));  
  86. }  
[cpp] view plain copy print ?
  1. [quagga@localhost socket]$   


SUID的作用就是这样:让本来没有相应权限的用户运行这个程序时,可以访问他没有权限访问的资源。

passwd就是一个很鲜明的例子。
SUID的优先级比SGID高,当一个可执行程序设置了SUID,则SGID会自动变成相应的egid。

下面讨论一个例子:
UNIX系统有一个/dev/kmem的设备文件,是一个字符设备文件,里面存储了核心程序要访问的数据,包括用户的口令。
所以这个文件不能给一般的用户读写,权限设为:

# ls -l /dev/kmem

[cpp] view plain copy print ?
  1. cr--r----- 1 root system 2, 1 May 25 1998 kmem  

但ps等程序要读这个文件,而ps的权限设置如下:
# ls -l /bin/ps

[cpp] view plain copy print ?
  1. -r-xr-sr-x 1 bin system 59346 Apr 05 1998 ps  

这是一个设置了SGID的程序,而ps的用户是bin,不是root,所以不能设置SUID来访问kmem,但大家注意了,
bin和root都属于system组,而且ps设置了SGID,一般用户执行ps,就会获得system组用户的权限,而文件kmem的
同组用户的权限是可读,所以一般用户执行ps就没问题了。但有些人说,为什么不把ps程序设置为root用户的程序,
然后设置SUID位,不也行吗?这的确可以解决问题,但实际中为什么不这样做呢?
因为SGID的风险比SUID小得多,所以出于系统安全的考虑,如果可能的话,应该尽量用SGID代替SUID的程序。

下面来说明一下SGID对目录的影响。
如果一个目录设置了SGID位,那么某用户(此用户对这个目录有写权限的话)在这个目录所建立的文件的组
都会自动转为这个目录的属主所在的组,而文件所有者不变,还是属于建立这个文件的用户。

[cpp] view plain copy print ?
  1. [zhang@localhost ctest]$ whoami  
  2. zhang  
  3. [zhang@localhost ctest]$ chmod o+w socket  
  4. [zhang@localhost ctest]$ ls -l | grep socket  
  5. drwxr-xrwx  3 zhang zhang     4096 2012-07-31 10:12 socket  
  6. [zhang@localhost ctest]$ chmod g+s socket  
  7. [zhang@localhost ctest]$  
  8. [zhang@localhost ctest]$ ls -l | grep socket  
  9. drwxr-srwx  3 zhang zhang     4096 2012-07-31 10:13 socket  
  10.   
  11. [quagga@localhost socket]$ whoami  
  12. quagga  
  13. [quagga@localhost socket]$ touch quagga  
  14. [quagga@localhost socket]$ ls -l quagga  
  15. -rw-rw-r-- 1 quagga zhang 0 2012-07-31 11:56 quagga  
  16. [quagga@localhost socket]$   


如果一个目录没有设置SGID位,那么某用户(此用户对这个目录有写权限的话)在这个目录下所建立文件的组
还是建立这个文件的用户所在的组,文件所有者还是属于建立这个文件的用户。

[cpp] view plain copy print ?
  1. [zhang@localhost ctest]$ whoami  
  2. zhang  
  3. [zhang@localhost ctest]$ chmod g-s socket  
  4. [zhang@localhost ctest]$ ls -l | grep socket  
  5. drwxr-xrwx  3 zhang zhang     4096 2012-07-31 11:56 socket  
  6. [zhang@localhost ctest]$  
  7.   
  8. [quagga@localhost socket]$ whoami  
  9. quagga  
  10. [quagga@localhost socket]$ touch quagga1  
  11. [quagga@localhost socket]$ ls -l quagga*  
  12. -rw-rw-r-- 1 quagga zhang  0 2012-07-31 11:56 quagga  
  13. -rw-rw-r-- 1 quagga quagga 0 2012-07-31 11:57 quagga1  
  14. [quagga@localhost socket]$  
  15. [quagga@localhost socket]$   



 

附录:

mycat.c 源码:

[cpp] view plain copy print ?
  1. /* 
  2.  
  3. * file name: mycat.c 
  4. * this program is from <unix network program(volume 1 third edition)> 15.7 "unix domain socket" 
  5. */  
  6.   
  7. #include <stdio.h>  
  8. #include <stdlib.h>     // for exit  
  9. #include <unistd.h>     // for write  
  10. #include <sys/wait.h>   // for WEXITSTATUS  
  11. #include <sys/un.h>     // for socketpair  
  12. #include <sys/socket.h> // for socketpair  
  13. #include <sys/types.h>  
  14. #include <sys/stat.h>   //for open  
  15. #include <fcntl.h>  
  16. #include <errno.h>  
  17.   
  18. int my_open(const char *pathname, int mode);  
  19. ssize_t read_fd(int fd, void *ptr, size_t nbytes, int *recvfd);  
  20.   
  21. int main(int argc, char **argv)  
  22. {  
  23.         int             fd, n;  
  24.         char    buf[10240];  
  25.   
  26.         if (argc != 2)  
  27.         {  
  28.                 fprintf(stderr, "usage: mycat <pathname>.\n");  
  29.                 return 0;  
  30.         }  
  31.   
  32.         if ( (fd = my_open(argv[1], O_RDONLY)) < 0)  
  33.         {  
  34.                 fprintf(stderr, "cannot open %s", argv[1]);  
  35.                 return 0;  
  36.         }  
  37.   
  38.         // while ( (n = read(fd, buf, sizeof(buf))) > 0)  
  39.         if( (n = read(fd, buf, sizeof(buf))) > 0)  
  40.         {  
  41.                 write(STDOUT_FILENO, buf, n);  
  42.         }  
  43.         else  
  44.         {  
  45.                 perror("read\n");  
  46.         }  
  47.   
  48.         exit(0);  
  49. }  
  50.   
  51. int my_open(const char *pathname, int mode)  
  52. {  
  53.         int                     fd, sockfd[2], status;  
  54.         pid_t           childpid;  
  55.         char            c, argsockfd[10], argmode[10];  
  56.   
  57.         socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);  
  58.   
  59.         if ( (childpid = fork()) == 0) /* child process */  
  60.         {  
  61.                 close(sockfd[0]);  
  62.                 snprintf(argsockfd, sizeof(argsockfd), "%d", sockfd[1]);  
  63.                 snprintf(argmode, sizeof(argmode), "%d", mode);  
  64.                 execl("./openfile""openfile", argsockfd, pathname, argmode, (char *) NULL);  
  65.                 fprintf(stderr, "execl error.\n");  
  66.         }  
  67.   
  68.         /* parent process */  
  69.         close(sockfd[1]);  
  70.   
  71.         /* wait for the child to terminate */  
  72.         waitpid(childpid, &status, 0);  
  73.   
  74.         if (WIFEXITED(status) == 0)  
  75.         {  
  76.                 fprintf(stderr, "child did not terminate.\n");  
  77.                 return 0;  
  78.         }  
  79.   
  80.         if ( (status = WEXITSTATUS(status)) == 0)  
  81.         {  
  82.                 read_fd(sockfd[0], &c, 1, &fd);  
  83.                 //read(sockfd[0], &fd, sizeof(int));  
  84.                 fprintf(stderr, "[%s-%d]: sockfd[0]=%d, sockfd[1]=%d, fd=%d, c=%c\n", __FUNCTION__, __LINE__, sockfd[0], sockfd[1], fd, c );  
  85.   
  86.         }  
  87.         else  
  88.         {  
  89.                 errno = status;         /* set errno value from child's status */  
  90.                 fd = -1;  
  91.         }  
  92.   
  93.         close(sockfd[0]);  
  94.         return(fd);  
  95. }  
  96.   
  97. ssize_t read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)  
  98. {  
  99.         struct msghdr msg;  
  100.         struct iovec iov[1];  
  101.         ssize_t n;  
  102.   
  103. #if 1  
  104.         union  
  105.         {  
  106.                 struct cmsghdr cm;  
  107.                 char control[CMSG_SPACE(sizeof(int))];  
  108.         } control_un;  
  109.   
  110.         struct cmsghdr *cmptr;  
  111.   
  112.         msg.msg_control = control_un.control;  
  113.         msg.msg_controllen = sizeof(control_un.control);  
  114. #else  
  115.         int                             newfd;  
  116.   
  117.         msg.msg_accrights = (caddr_t) &newfd;  
  118.         msg.msg_accrightslen = sizeof(int);  
  119. #endif  
  120.   
  121.         msg.msg_name = NULL;  
  122.         msg.msg_namelen = 0;  
  123.   
  124.         iov[0].iov_base = ptr;  
  125.         iov[0].iov_len = nbytes;  
  126.         msg.msg_iov = iov;  
  127.         msg.msg_iovlen = 1;  
  128.   
  129.         if ( (n = recvmsg(fd, &msg, 0)) <= 0)  
  130.                 return(n);  
  131.   
  132. #if 1  
  133.         if ( (cmptr = CMSG_FIRSTHDR(&msg)) != NULL && cmptr->cmsg_len == CMSG_LEN(sizeof(int)))  
  134.         {  
  135.                 if (cmptr->cmsg_level != SOL_SOCKET)  
  136.                 {  
  137.                         fprintf(stderr, "control level != SOL_SOCKET\n");  
  138.                 }  
  139.   
  140.                 if (cmptr->cmsg_type != SCM_RIGHTS)  
  141.                 {  
  142.                         fprintf(stderr, "control type != SCM_RIGHTS\n");  
  143.                 }  
  144.                 *recvfd = *((int *) CMSG_DATA(cmptr));  
  145.         }  
  146.         else  
  147.         {  
  148.                 *recvfd = -1;           /* descriptor was not passed */  
  149.         }  
  150. #else  
  151. /* *INDENT-OFF* */  
  152.         if (msg.msg_accrightslen == sizeof(int))  
  153.                 *recvfd = newfd;  
  154.         else  
  155.                 *recvfd = -1;           /* descriptor was not passed */  
  156. /* *INDENT-ON* */  
  157. #endif  
  158.   
  159.         return(n);  
  160. }  


 


openfile.c源码:

[cpp] view plain copy print ?
  1. /* 
  2.  
  3. * file name: openfile.c 
  4. * this program is excuted by program of "mycat", 
  5. * execl("./openfile", "openfile", argsockfd, pathname, argmode, (char *) NULL); 
  6. * 
  7. */  
  8.   
  9. #include <stdio.h>  
  10. #include <unistd.h>  
  11. #include <stdlib.h>  
  12. #include <errno.h>  
  13. #include <sys/types.h>  
  14. #include <sys/socket.h>  
  15.   
  16. ssize_t write_fd(int fd, void *ptr, size_t nbytes, int sendfd);  
  17.   
  18. int main(int argc, char **argv)  
  19. {  
  20.         int fd = -1, n = 0;  
  21.         char buf[10240] = {0};  
  22.   
  23.         if (argc != 4)  
  24.         {  
  25.                 fprintf(stderr, "openfile <sockfd#> <filename> <mode>\n");  
  26.                 exit(255);  
  27.         }  
  28.   
  29.         if ( (fd = open(argv[2], atoi(argv[3]))) < 0 )  
  30.         {  
  31.                 exit( (errno > 0) ? errno : 255 );  
  32.         }  
  33.   
  34.         /* 
  35.         n = read(fd, buf, sizeof(buf)); 
  36.         write(STDOUT_FILENO, buf, n); 
  37.         */  
  38.   
  39.         if ( write_fd(atoi(argv[1]), "x", 1, fd) < 0 )  
  40.         // if ( write(atoi(argv[1]), &fd, sizeof(int)) < 0 )  
  41.         {  
  42.                 exit( (errno > 0) ? errno : 255 );  
  43.         }  
  44.   
  45.         fprintf(stderr, "[%s-%d]: sockfd[1]=%d, fd=%d\n", __FILE__, __LINE__, atoi(argv[1]), fd );  
  46.   
  47.         exit(0);  
  48. }  
  49.   
  50. ssize_t write_fd(int fd, void *ptr, size_t nbytes, int sendfd)  
  51. {  
  52.         struct msghdr msg;  
  53.         struct iovec    iov[1];  
  54.   
  55. #if 1  
  56.         union  
  57.         {  
  58.                 struct cmsghdr cm;  
  59.                 char control[CMSG_SPACE(sizeof(int))];  
  60.         } control_un;  
  61.   
  62.         struct cmsghdr *cmptr;  
  63.   
  64.         msg.msg_control = control_un.control;  
  65.         msg.msg_controllen = sizeof(control_un.control);  
  66.   
  67.         cmptr = CMSG_FIRSTHDR(&msg);  
  68.         cmptr->cmsg_len = CMSG_LEN(sizeof(int));  
  69.         cmptr->cmsg_level = SOL_SOCKET;  
  70.         cmptr->cmsg_type = SCM_RIGHTS;  
  71.         *((int *) CMSG_DATA(cmptr)) = sendfd;  
  72. #else  
  73.         msg.msg_accrights = (caddr_t) &sendfd;  
  74.         msg.msg_accrightslen = sizeof(int);  
  75. #endif  
  76.   
  77.         msg.msg_name = NULL;  
  78.         msg.msg_namelen = 0;  
  79.   
  80.         iov[0].iov_base = ptr;  
  81.         iov[0].iov_len = nbytes;  
  82.         msg.msg_iov = iov;  
  83.         msg.msg_iovlen = 1;  
  84.   
  85.         return(sendmsg(fd, &msg, 0));  
  86. }  


//todo

你可能感兴趣的:(SUID,SGID)