关于UNIXDOMAIN协议的接收发送者验证

来源:互联网 发布:行知职高放假 编辑:程序博客网 时间:2024/05/16 04:51

在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_unserv, cli;

intlistenfd, connfd;

socklen_tclilen;

struct cmsgcredcred;

charbuf[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 msghdrmsg;

struct ioveciov[1];

ssize_tn;

union {

struct cmsghdrcm;

charcontrol[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_unserv;

intsockfd;

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 msghdrmsg;

struct ioveciov[1];

union {

struct cmsghdrcm;

charcontrol[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));

}

原创粉丝点击