博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于UNIXDOMAIN协议的接收发送者验证
阅读量:4027 次
发布时间:2019-05-24

本文共 8272 字,大约阅读时间需要 27 分钟。

在Linux上,

1) receiver 要 setsockopt SO_PASSCRED
2) sender 要显式的调用 sendmsg [cmsg_type SCM_CRENDENTIALS, cmsg_data 为 ucred 并由 sender 填充 (kernel会作检验,如果pid/uid/gid不正确, 则会报错 "Operation not permitted" )]
3) receiver 用 recvmsg 接收。
在 FreeBSD 上,
1) receiver 无需设定 socket选项,直接用 recvmsg 接收。
2) sender 用 sendmsg 发送一个 cmsg_type 为 SCM_CREDS 的 msg (相关结构为 struct cmsgcred, 这个无需 sender 显式填充, kernel会填入cmsgcred的相关成员值)
/* Based on the UNP's code, tested on kernel 2.4.20-8 */
/* server.c  --  credentials receiver */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <linux/socket.h>
#define PATH "./myserv.unix"
typedef struct sockaddr SA;
static ssize_t read_cred(int, void *, size_t, struct ucred *);
int main(void)
{
        struct sockaddr_un      serv, cli;
        int                     listenfd, connfd;
        socklen_t               clilen;
        struct ucred            cred;
        char                    buf[10];
        const int               on = 1;
        if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
                perror("socket error");
                exit(1);
        }
        memset(&serv, 0, sizeof(serv));
        serv.sun_family = AF_LOCAL;
        unlink(PATH);
        strncpy(serv.sun_path, PATH, sizeof(serv.sun_path) - 1);
        if (bind(listenfd, (SA *) &serv, sizeof(serv)) < 0) {
                perror("bind error");
                exit(1);
        }
        if (listen(listenfd, 1024) < 0) {
                perror("listen error");
                exit(1);
        }
        for ( ; ; ) {
                clilen = sizeof(cli);
                if ((connfd = accept(listenfd, (SA *) &cli, &clilen)) < 0)
{
                        if (errno == EINTR)
                                continue;
                        else {
                                perror("accept error");
                                exit(1);
                        }
                }
                if (setsockopt(connfd, SOL_SOCKET, SO_PASSCRED, &on,
                        sizeof(on)) < 0) {
                        perror("setsockopt error");
                        exit(1);
                }
                if (read_cred(connfd, buf, 5, &cred) < 0) {
                        perror("read_cred error");
                        exit(1);
                }
                buf[5] = '/0';
                printf("read data: %s/n", buf);
                printf("pid = %d, uid = %d, gid = %d/n", cred.pid,
                            cred.uid, cred.gid);
        }
        return 0;
}
static ssize_t
read_cred(int fd, void *ptr, size_t nbytes, struct ucred *credptr)
{
        struct msghdr   msg;
        struct iovec    iov[1];
        ssize_t         n;
        union {
                struct cmsghdr  cm;
char control[CMSG_SPACE(sizeof(struct ucred))];
        } control_un;
        struct cmsghdr  *cmptr;
        msg.msg_control = control_un.control;
        msg.msg_controllen = sizeof(control_un.control);
        msg.msg_name = NULL;
        msg.msg_namelen = 0;
        iov[0].iov_base = ptr;
        iov[0].iov_len = nbytes;
        msg.msg_iov = iov;
        msg.msg_iovlen = 1;
        if ((n = recvmsg(fd, &msg, 0)) < 0)
                return n;
        if (credptr) {
                if (msg.msg_controllen > sizeof(struct cmsghdr)) {
                        cmptr = CMSG_FIRSTHDR(&msg);
                        if (cmptr->cmsg_len != CMSG_LEN(
                  sizeof(struct ucred))) {
                                fprintf(stderr, "cmsg_len error/n");
                                exit(1);
                        }
                        if (cmptr->cmsg_level != SOL_SOCKET) {
                                fprintf(stderr, "cmsg_level != SOL_SOCKET/n");
                                exit(1);
                        }
                        if (cmptr->cmsg_type != SCM_CREDENTIALS) {
                                fprintf(stderr, "cmsg_type != SCM_CREDENTIALS/n"
);
                                exit(1);
                        }
                        memcpy(credptr, CMSG_DATA(cmptr),
                            sizeof(struct ucred));
                } else
                        memset(credptr, 0, sizeof(struct ucred));
        }
        return n;
}
/* client.c  --  credentials sender */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <linux/socket.h>
#define PATH "./myserv.unix"
typedef struct sockaddr SA;
static ssize_t write_cred(int, void *, size_t);
int main(void)
{
        struct sockaddr_un      serv;
        int                     sockfd;
        char                    *buf = "hello";
        if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
                perror("socket error");
                exit(1);
        }
        memset(&serv, 0, sizeof(serv));
        serv.sun_family = AF_LOCAL;
        strncpy(serv.sun_path, PATH, sizeof(serv.sun_path) - 1);
        if (connect(sockfd, (SA *)&serv, sizeof(serv)) < 0) {
                perror("connect error");
                exit(1);
        }
        if (write_cred(sockfd, buf, 5) < 0) {
                perror("write_cred error");
                exit(1);
        }
        return 0;
}
static ssize_t write_cred(int fd, void *ptr, size_t nbytes)
{
        struct msghdr   msg;
        struct iovec    iov[1];
        union {
                struct cmsghdr  cm;
                char            control[CMSG_SPACE(sizeof(struct ucred))];
        } control_un;
        struct cmsghdr  *cmptr;
        struct ucred    *ucptr;
        msg.msg_control = control_un.control;
        msg.msg_controllen = sizeof(control_un.control);
        cmptr = CMSG_FIRSTHDR(&msg);
        cmptr->cmsg_len = CMSG_LEN(sizeof(struct ucred));
        cmptr->cmsg_level = SOL_SOCKET;
        cmptr->cmsg_type = SCM_CREDENTIALS;
        ucptr = (struct ucred *) CMSG_DATA(cmptr);
        ucptr->pid = getpid();
        ucptr->uid = getuid();
        ucptr->gid = getgid();
        msg.msg_name = NULL;
        msg.msg_namelen = 0;
        iov[0].iov_base = ptr;
        iov[0].iov_len = nbytes;
        msg.msg_iov = iov;
        msg.msg_iovlen = 1;
        return (sendmsg(fd, &msg, 0));
}
/* Based on the UNP's code, tested on FreeBSD 4.7-Release */
/* server.c -- creds receiver */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define PATH "./myserv.unix"
typedef struct sockaddr SA;
static ssize_t read_cred(int, void *, size_t, struct cmsgcred *);
int main(void)
{
struct sockaddr_un serv, cli;
int listenfd, connfd;
socklen_t clilen;
struct cmsgcred cred;
char buf[10];
if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
perror("socket error");
exit(1);
}
memset(&serv, 0, sizeof(serv));
serv.sun_family = AF_LOCAL;
unlink(PATH);
strncpy(serv.sun_path, PATH, sizeof(serv.sun_path) - 1);
if (bind(listenfd, (SA *) &serv, sizeof(serv)) < 0) {
perror("bind error");
exit(1);
}
if (listen(listenfd, 1024) < 0) {
perror("listen error");
exit(1);
}
for ( ; ; ) {
clilen = sizeof(cli);
if ((connfd = accept(listenfd, (SA *) &cli, &clilen)) < 0) {
if (errno == EINTR)
continue;
else {
perror("accept error");
exit(1);
}
}
if (read_cred(connfd, buf, 5, &cred) < 0) {
perror("read_cred error");
exit(1);
}
buf[5] = '/0';
printf("read data: %s/n", buf);
if (cred.cmcred_ngroups == 0)
printf("no credentials returned/n");
else
printf("pid = %d, uid = %d, euid = %d, "
    "gid = %d/n", cred.cmcred_pid,
    cred.cmcred_uid, cred.cmcred_euid,
    cred.cmcred_gid);
}
return 0;
}
static ssize_t
read_cred(int fd, void *ptr, size_t nbytes, struct cmsgcred *credptr)
{
struct msghdr msg;
struct iovec iov[1];
ssize_t n;
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(struct cmsgcred))];
} control_un;
struct cmsghdr *cmptr;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov[0].iov_base = ptr;
iov[0].iov_len = nbytes;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
if ((n = recvmsg(fd, &msg, 0)) < 0)
return n;
if (credptr) {
if (msg.msg_controllen > sizeof(struct cmsghdr)) {
cmptr = CMSG_FIRSTHDR(&msg);
if (cmptr->cmsg_len != CMSG_LEN(
    sizeof(struct cmsgcred))) {
fprintf(stderr, "cmsg_len error/n");
exit(1);
}
if (cmptr->cmsg_level != SOL_SOCKET) {
fprintf(stderr, "cmsg_level != SOL_SOCKET/n");
exit(1);
}
if (cmptr->cmsg_type != SCM_CREDS) {
fprintf(stderr, "cmsg_type != SCM_CREDS/n");
exit(1);
}
memcpy(credptr, CMSG_DATA(cmptr),
    sizeof(struct cmsgcred));
} else
memset(credptr, 0, sizeof(struct cmsgcred));
}
return n;
}
/* client.c -- creds sender */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define PATH "./myserv.unix"
typedef struct sockaddr SA;
static ssize_t write_cred(int, void *, size_t);
int main(void)
{
struct sockaddr_un serv;
int sockfd;
char *buf = "hello";
if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
perror("socket error");
exit(1);
}
memset(&serv, 0, sizeof(serv));
serv.sun_family = AF_LOCAL;
strncpy(serv.sun_path, PATH, sizeof(serv.sun_path) - 1);
if (connect(sockfd, (SA *)&serv, sizeof(serv)) < 0) {
perror("connect error");
exit(1);
}
if (write_cred(sockfd, buf, 5) < 0) {
perror("write_cred error");
exit(1);
}
return 0;
}
static ssize_t write_cred(int fd, void *ptr, size_t nbytes)
{
struct msghdr msg;
struct iovec iov[1];
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(struct cmsgcred))];
} control_un;
struct cmsghdr *cmptr;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
cmptr = CMSG_FIRSTHDR(&msg);
cmptr->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_CREDS;
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov[0].iov_base = ptr;
iov[0].iov_len = nbytes;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
return (sendmsg(fd, &msg, 0));
}

转载地址:http://ntpbi.baihongyu.com/

你可能感兴趣的文章
利用清华镜像站解决pip超时问题
查看>>
[leetcode BY python]1两数之和
查看>>
微信小程序开发全线记录
查看>>
Centos import torchvision 出现 No module named ‘_lzma‘
查看>>
网页设计里的浮动 属性
查看>>
Maximum Subsequence Sum
查看>>
PTA:一元多项式的加乘运算
查看>>
CCF 分蛋糕
查看>>
解决python2.7中UnicodeEncodeError
查看>>
小谈python 输出
查看>>
Django objects.all()、objects.get()与objects.filter()之间的区别介绍
查看>>
python:如何将excel文件转化成CSV格式
查看>>
Django 的Error: [Errno 10013]错误
查看>>
机器学习实战之决策树(一)
查看>>
[LeetCode By Python] 2 Add Two Number
查看>>
python 中的 if __name__=='__main__' 作用
查看>>
机器学习实战之决策树二
查看>>
[LeetCode By Python]7 Reverse Integer
查看>>
[LeetCode By Python]9. Palindrome Number
查看>>
[leetCode By Python] 14. Longest Common Prefix
查看>>