关于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));
}
- 关于UNIXDOMAIN协议的接收发送者验证
- JAVA Http协议的发送接收
- JAVA TCP协议的发送接收
- xmodem协议 文件接收发送
- 投票协议:发送和接收
- udp协议的数据接收与发送的代码
- Android发送接收短信的代码示例(本人验证OK)
- IBMMQ 带用户密码验证的发送和接收消息
- 基于TCP协议的发送和接收端
- 发送缓冲区、接收缓冲区、滑动窗口协议之间的关系
- UDT4协议源码分析之数据的发送和接收
- 基于UDP协议的接收和发送实验
- UDP传输协议的基本应用-发送和接收
- UDP 用户数据报文协议的发送和接收示例
- 关于SMTP协议发送邮件的总结
- 关于Windows消息的发送和接收入门
- 关于Windows消息的发送和接收入门
- WinSock中关于阻塞接收/发送超时的一个BUG
- [Android]获取未安装的APK图标(原创非转帖)
- GetCurrentProcessID、OpenProcessToken、LookupPrivilegeValue、AdjustTokenPrivileges
- CentOs5.3下filebench安装
- 树的三种遍历
- Repeater实现批量删除
- 关于UNIXDOMAIN协议的接收发送者验证
- C# 编写的一个简单的 HTTP 服务器
- mini球带IR-CUT功能
- 一位来自《seo实战密码》读者的来信
- 新手上路,matlab基础(1)
- Tuning Apache and PHP for Speed on Unix
- 潘金莲——中国女性解放思想的先驱《其实我的心没走》
- mfc中的隐藏问题(转载)
- HOWTO on Optimizing PHP