本文共 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_tread_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_tread_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/