#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
static int
server(struct sockaddr_un *addr)
{
int ret;
pid_t pid;
int sock;
unsigned int i;
pid = fork();
if (pid == (pid_t)-1) {
fprintf(stderr, "server - fork fail %s\n", strerror(errno));
return (-1);
}
if (pid != 0) {
return (0);
}
sock = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sock == -1) {
fprintf(stderr, "server - socket fail %s\n", strerror(errno));
exit(1);
}
ret = bind(sock, (struct sockaddr *)addr, sizeof (*addr));
if (ret == -1) {
fprintf(stderr, "server - bind fail %s\n", strerror(errno));
exit(1);
}
for (i = 0; i < 5; i++) {
struct iovec iov;
struct msghdr msg;
uint8_t buf[4096];
iov = (struct iovec) {
.iov_base = buf,
.iov_len = sizeof (buf)
};
msg = (struct msghdr) {
.msg_iov = &iov,
.msg_iovlen = 1,
};
ret = recvmsg(sock, &msg, 0);
if (ret == -1) {
fprintf(stderr, "server - recvmsg fail %s\n",
strerror(errno));
exit(1);
}
printf("SERVER:%s\n", (char *)msg.msg_iov->iov_base);
fflush(stdout);
}
exit(0);
}
static void
non_priv_send(struct sockaddr_un *addr, int uid)
{
pid_t pid;
int sock;
int ret;
struct iovec iov;
struct msghdr msg;
uint8_t buf[4096];
pid = fork();
if (pid == (pid_t)-1) {
fprintf(stderr, "non_priv_send - fork fail %s\n",
strerror(errno));
return;
}
if (pid != 0) {
return;
}
memcpy(buf, "TEST1\n", sizeof ("TEST1\n"));
iov = (struct iovec) {
.iov_base = buf,
.iov_len = sizeof (buf),
};
msg = (struct msghdr) {
.msg_name = addr,
.msg_namelen = sizeof (*addr),
.msg_iov = &iov,
.msg_iovlen = 1,
};
sock = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sock == -1) {
fprintf(stderr, "non_priv_send - socket fail %s\n",
strerror(errno));
exit(1);
}
ret = setreuid(uid, uid);
if (ret == -1) {
fprintf(stderr, "non_priv_send - setresuid fail %s\n",
strerror(errno));
exit(1);
}
ret = sendmsg(sock, &msg, 0);
if (ret == -1) {
printf("non_priv_send - sendmsg fail (expected) %s\n",
strerror(errno));
exit(0);
}
fprintf(stderr, "non_priv_send - UNEXPECTED sendmsg OK\n");
exit(1);
}
char testdir[100] = "/var/run/os-tests-sockfs";
struct sockaddr_un addr;
int test_uid = UID_NOBODY;
int
main(int argc, char **argv)
{
int ret;
int sock;
unsigned int i;
uid_t us = geteuid();
if (us != 0) {
fprintf(stderr, "%s: need to be root\n", argv[0]);
exit(1);
}
if (argc > 1) {
ret = strlcpy(testdir, argv[1], sizeof (testdir));
if (ret >= sizeof (testdir)) {
fprintf(stderr, "%s: too long\n", argv[1]);
exit(1);
}
}
addr.sun_family = AF_UNIX;
(void) sprintf(addr.sun_path, "%s/s", testdir);
if (mkdir(testdir, 0700) != 0) {
switch (errno) {
case EEXIST:
case EISDIR:
break;
default:
perror(testdir);
exit(1);
}
}
(void) unlink(addr.sun_path);
ret = server(&addr);
if (ret == -1) {
fprintf(stderr, "%s - server fork fail %s\n",
argv[0], strerror(errno));
exit(1);
}
sleep(1);
non_priv_send(&addr, test_uid);
sleep(1);
sock = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sock == -1) {
fprintf(stderr, "%s - socket fail %s\n",
argv[0], strerror(errno));
exit(1);
}
ret = connect(sock, (struct sockaddr *)&addr, sizeof (addr));
if (ret == -1) {
fprintf(stderr, "%s - connect fail %s\n",
argv[0], strerror(errno));
exit(1);
}
ret = setreuid(test_uid, test_uid);
if (ret == -1) {
printf("%s - setresuid fail %s\n",
argv[0], strerror(errno));
exit(1);
}
for (i = 0; i < 5; i++) {
struct iovec iov;
struct msghdr msg;
uint8_t buf[4096];
memcpy(buf, "TEST0", sizeof ("TEST0"));
buf[4] = '0' + i;
printf("CLIENT:%s\n", buf);
iov = (struct iovec) {
.iov_base = buf,
.iov_len = sizeof (buf),
};
msg = (struct msghdr) {
.msg_iov = &iov,
.msg_iovlen = 1,
};
ret = sendmsg(sock, &msg, 0);
if (ret == -1) {
fprintf(stderr, "%s - sendmsg fail %s\n",
argv[0], strerror(errno));
exit(1);
}
fflush(stdout);
sleep(1);
}
close(sock);
return (0);
}