182657471SMarkus Pfeiffer /**
282657471SMarkus Pfeiffer * Copyright (c) 2013 Larisa Grigore. All rights reserved.
382657471SMarkus Pfeiffer *
482657471SMarkus Pfeiffer * Redistribution and use in source and binary forms, with or without
582657471SMarkus Pfeiffer * modification, are permitted provided that the following conditions
682657471SMarkus Pfeiffer * are met:
782657471SMarkus Pfeiffer * 1. Redistributions of source code must retain the above copyright
882657471SMarkus Pfeiffer * notice, this list of conditions and the following disclaimer.
982657471SMarkus Pfeiffer * 2. Redistributions in binary form must reproduce the above copyright
1082657471SMarkus Pfeiffer * notice, this list of conditions and the following disclaimer in the
1182657471SMarkus Pfeiffer * documentation and/or other materials provided with the distribution.
1282657471SMarkus Pfeiffer * 3. The name of the author may not be used to endorse or promote products
1382657471SMarkus Pfeiffer * derived from this software without specific prior written permission.
1482657471SMarkus Pfeiffer *
1582657471SMarkus Pfeiffer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1682657471SMarkus Pfeiffer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1782657471SMarkus Pfeiffer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1882657471SMarkus Pfeiffer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1982657471SMarkus Pfeiffer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2082657471SMarkus Pfeiffer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2182657471SMarkus Pfeiffer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2282657471SMarkus Pfeiffer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2382657471SMarkus Pfeiffer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2482657471SMarkus Pfeiffer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2582657471SMarkus Pfeiffer */
2682657471SMarkus Pfeiffer
2782657471SMarkus Pfeiffer #include <sys/param.h>
2882657471SMarkus Pfeiffer #include <sys/un.h>
2982657471SMarkus Pfeiffer #include <sys/uio.h>
3082657471SMarkus Pfeiffer #include <sys/types.h>
3182657471SMarkus Pfeiffer #include <sys/stat.h>
3282657471SMarkus Pfeiffer #include <err.h>
3382657471SMarkus Pfeiffer #include <errno.h>
3482657471SMarkus Pfeiffer #include <fcntl.h>
3582657471SMarkus Pfeiffer #include <signal.h>
3682657471SMarkus Pfeiffer #include <stdio.h>
3782657471SMarkus Pfeiffer #include <stdlib.h>
3882657471SMarkus Pfeiffer #include <string.h>
3982657471SMarkus Pfeiffer #include <unistd.h>
4082657471SMarkus Pfeiffer
4182657471SMarkus Pfeiffer #include "sysvipc_utils.h"
4282657471SMarkus Pfeiffer #include "sysvipc_sockets.h"
4382657471SMarkus Pfeiffer
4482657471SMarkus Pfeiffer #define MAX_CONN 10
4582657471SMarkus Pfeiffer
4682657471SMarkus Pfeiffer int
init_socket(const char * sockfile)4782657471SMarkus Pfeiffer init_socket(const char *sockfile)
4882657471SMarkus Pfeiffer {
4982657471SMarkus Pfeiffer struct sockaddr_un un_addr;
5082657471SMarkus Pfeiffer int sock;
5182657471SMarkus Pfeiffer
5282657471SMarkus Pfeiffer /* create server socket */
5382657471SMarkus Pfeiffer if ( (sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
5482657471SMarkus Pfeiffer sysv_print_err("init socket");
5582657471SMarkus Pfeiffer return (-1);
5682657471SMarkus Pfeiffer }
5782657471SMarkus Pfeiffer
5882657471SMarkus Pfeiffer /* bind it */
5982657471SMarkus Pfeiffer memset(&un_addr, 0, sizeof(un_addr));
6082657471SMarkus Pfeiffer un_addr.sun_len = sizeof(un_addr);
6182657471SMarkus Pfeiffer un_addr.sun_family = AF_UNIX;
6282657471SMarkus Pfeiffer strcpy(un_addr.sun_path, sockfile);
6382657471SMarkus Pfeiffer
6482657471SMarkus Pfeiffer unlink(un_addr.sun_path);
6582657471SMarkus Pfeiffer
6682657471SMarkus Pfeiffer if (bind(sock, (struct sockaddr *)&un_addr, sizeof(un_addr)) < 0) {
6782657471SMarkus Pfeiffer close(sock);
6882657471SMarkus Pfeiffer sysv_print_err("bind");
6982657471SMarkus Pfeiffer return (-1);
7082657471SMarkus Pfeiffer }
7182657471SMarkus Pfeiffer
7282657471SMarkus Pfeiffer if (listen(sock, MAX_CONN) < 0) {
7382657471SMarkus Pfeiffer close(sock);
7482657471SMarkus Pfeiffer sysv_print_err("listen");
7582657471SMarkus Pfeiffer return (-1);
7682657471SMarkus Pfeiffer }
7782657471SMarkus Pfeiffer
7882657471SMarkus Pfeiffer /* turn on credentials passing */
7982657471SMarkus Pfeiffer return (sock);
8082657471SMarkus Pfeiffer }
8182657471SMarkus Pfeiffer
8282657471SMarkus Pfeiffer int
handle_new_connection(int sock)8382657471SMarkus Pfeiffer handle_new_connection(int sock)
8482657471SMarkus Pfeiffer {
8582657471SMarkus Pfeiffer int fd, flags;
8682657471SMarkus Pfeiffer
8782657471SMarkus Pfeiffer do {
8882657471SMarkus Pfeiffer fd = accept(sock, NULL, NULL);
8982657471SMarkus Pfeiffer } while (fd < 0 && errno == EINTR);
9082657471SMarkus Pfeiffer
9182657471SMarkus Pfeiffer if (fd < 0) {
9282657471SMarkus Pfeiffer sysv_print_err("accept");
9382657471SMarkus Pfeiffer return (-1);
9482657471SMarkus Pfeiffer }
9582657471SMarkus Pfeiffer
9682657471SMarkus Pfeiffer flags = fcntl(fd, F_GETFL, 0);
9782657471SMarkus Pfeiffer fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
9882657471SMarkus Pfeiffer
9982657471SMarkus Pfeiffer return (fd);
10082657471SMarkus Pfeiffer }
10182657471SMarkus Pfeiffer
10282657471SMarkus Pfeiffer int
connect_to_daemon(const char * sockfile)10382657471SMarkus Pfeiffer connect_to_daemon(const char *sockfile)
10482657471SMarkus Pfeiffer {
10582657471SMarkus Pfeiffer int sock, flags;
10682657471SMarkus Pfeiffer struct sockaddr_un serv_addr;
10782657471SMarkus Pfeiffer
10882657471SMarkus Pfeiffer if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
10982657471SMarkus Pfeiffer sysv_print_err("socket(%d)\n", sock);
11082657471SMarkus Pfeiffer return (-1);
11182657471SMarkus Pfeiffer }
11282657471SMarkus Pfeiffer
11382657471SMarkus Pfeiffer flags = fcntl(sock, F_GETFL, 0);
11482657471SMarkus Pfeiffer fcntl(sock, F_SETFL, flags & ~O_NONBLOCK);
11582657471SMarkus Pfeiffer
11682657471SMarkus Pfeiffer memset(&serv_addr, 0, sizeof(serv_addr));
11782657471SMarkus Pfeiffer serv_addr.sun_family = AF_UNIX;
11882657471SMarkus Pfeiffer strcpy(serv_addr.sun_path, sockfile);
11982657471SMarkus Pfeiffer
12082657471SMarkus Pfeiffer if (connect(sock, (struct sockaddr *)&serv_addr,
12182657471SMarkus Pfeiffer sizeof(serv_addr)) < 0) {
12282657471SMarkus Pfeiffer close(sock);
12382657471SMarkus Pfeiffer sysv_print_err("connect(%d)\n", sock);
12482657471SMarkus Pfeiffer return (-1);
12582657471SMarkus Pfeiffer }
12682657471SMarkus Pfeiffer
12782657471SMarkus Pfeiffer return (sock);
12882657471SMarkus Pfeiffer }
12982657471SMarkus Pfeiffer
13082657471SMarkus Pfeiffer int
send_fd(int sock,int fd)13182657471SMarkus Pfeiffer send_fd(int sock, int fd)
13282657471SMarkus Pfeiffer {
13382657471SMarkus Pfeiffer struct msghdr msg;
13482657471SMarkus Pfeiffer struct iovec vec;
13582657471SMarkus Pfeiffer #ifndef HAVE_ACCRIGHTS_IN_MSGHDR
13682657471SMarkus Pfeiffer union {
13782657471SMarkus Pfeiffer struct cmsghdr hdr;
13882657471SMarkus Pfeiffer char buf[CMSG_SPACE(sizeof(int))];
13982657471SMarkus Pfeiffer } cmsgbuf;
14082657471SMarkus Pfeiffer struct cmsghdr *cmsg;
14182657471SMarkus Pfeiffer #endif
14282657471SMarkus Pfeiffer int result = 0;
14382657471SMarkus Pfeiffer ssize_t n;
14482657471SMarkus Pfeiffer
14582657471SMarkus Pfeiffer memset(&msg, 0, sizeof(msg));
14682657471SMarkus Pfeiffer
14782657471SMarkus Pfeiffer if (fd < 0)
14882657471SMarkus Pfeiffer result = errno;
14982657471SMarkus Pfeiffer else {
15082657471SMarkus Pfeiffer #ifdef HAVE_ACCRIGHTS_IN_MSGHDR
15182657471SMarkus Pfeiffer msg.msg_accrights = (caddr_t)&fd;
15282657471SMarkus Pfeiffer msg.msg_accrightslen = sizeof(fd);
15382657471SMarkus Pfeiffer #else
15482657471SMarkus Pfeiffer msg.msg_control = (caddr_t)cmsgbuf.buf;
15582657471SMarkus Pfeiffer msg.msg_controllen = sizeof(cmsgbuf.buf);
15682657471SMarkus Pfeiffer cmsg = CMSG_FIRSTHDR(&msg);
15782657471SMarkus Pfeiffer cmsg->cmsg_len = CMSG_LEN(sizeof(int));
15882657471SMarkus Pfeiffer cmsg->cmsg_level = SOL_SOCKET;
15982657471SMarkus Pfeiffer cmsg->cmsg_type = SCM_RIGHTS;
16082657471SMarkus Pfeiffer *(int *)CMSG_DATA(cmsg) = fd;
16182657471SMarkus Pfeiffer #endif
16282657471SMarkus Pfeiffer }
16382657471SMarkus Pfeiffer
16482657471SMarkus Pfeiffer vec.iov_base = (caddr_t)&result;
16582657471SMarkus Pfeiffer vec.iov_len = sizeof(int);
16682657471SMarkus Pfeiffer msg.msg_iov = &vec;
16782657471SMarkus Pfeiffer msg.msg_iovlen = 1;
16882657471SMarkus Pfeiffer
16982657471SMarkus Pfeiffer if ((n = sendmsg(sock, &msg, 0)) == -1) {
17040d436c0SSascha Wildner sysv_print_err("sendmsg(%d)\n", sock);
17182657471SMarkus Pfeiffer return (-1);
17282657471SMarkus Pfeiffer }
17382657471SMarkus Pfeiffer if (n != sizeof(int)) {
17482657471SMarkus Pfeiffer sysv_print_err("sendmsg: expected sent 1 got %ld\n",
17582657471SMarkus Pfeiffer (long)n);
17682657471SMarkus Pfeiffer return (-1);
17782657471SMarkus Pfeiffer }
17882657471SMarkus Pfeiffer
17982657471SMarkus Pfeiffer return (0);
18082657471SMarkus Pfeiffer }
18182657471SMarkus Pfeiffer
18282657471SMarkus Pfeiffer /**/
18382657471SMarkus Pfeiffer int
receive_fd(int sock)18482657471SMarkus Pfeiffer receive_fd(int sock)
18582657471SMarkus Pfeiffer {
18682657471SMarkus Pfeiffer struct msghdr msg;
18782657471SMarkus Pfeiffer struct iovec vec;
18882657471SMarkus Pfeiffer #ifndef HAVE_ACCRIGHTS_IN_MSGHDR
18982657471SMarkus Pfeiffer union {
19082657471SMarkus Pfeiffer struct cmsghdr hdr;
19182657471SMarkus Pfeiffer char buf[CMSG_SPACE(sizeof(int))];
19282657471SMarkus Pfeiffer } cmsgbuf;
19382657471SMarkus Pfeiffer struct cmsghdr *cmsg;
19482657471SMarkus Pfeiffer #endif
19582657471SMarkus Pfeiffer ssize_t n;
19682657471SMarkus Pfeiffer int result;
19782657471SMarkus Pfeiffer int fd;
19882657471SMarkus Pfeiffer
19982657471SMarkus Pfeiffer memset(&msg, 0, sizeof(msg));
20082657471SMarkus Pfeiffer vec.iov_base = (caddr_t)&result;
20182657471SMarkus Pfeiffer vec.iov_len = sizeof(int);
20282657471SMarkus Pfeiffer msg.msg_iov = &vec;
20382657471SMarkus Pfeiffer msg.msg_iovlen = 1;
20482657471SMarkus Pfeiffer
20582657471SMarkus Pfeiffer #ifdef HAVE_ACCRIGHTS_IN_MSGHDR
20682657471SMarkus Pfeiffer msg.msg_accrights = (caddr_t)&fd;
20782657471SMarkus Pfeiffer msg.msg_accrightslen = sizeof(fd);
20882657471SMarkus Pfeiffer #else
20982657471SMarkus Pfeiffer msg.msg_control = &cmsgbuf.buf;
21082657471SMarkus Pfeiffer msg.msg_controllen = sizeof(cmsgbuf.buf);
21182657471SMarkus Pfeiffer #endif
21282657471SMarkus Pfeiffer
21382657471SMarkus Pfeiffer if ((n = recvmsg(sock, &msg, 0)) == -1)
21482657471SMarkus Pfeiffer sysv_print_err("recvmsg\n");
21582657471SMarkus Pfeiffer if (n != sizeof(int)) {
21682657471SMarkus Pfeiffer sysv_print_err("recvmsg: expected received 1 got %ld\n",
21782657471SMarkus Pfeiffer (long)n);
21882657471SMarkus Pfeiffer }
21982657471SMarkus Pfeiffer if (result == 0) {
22082657471SMarkus Pfeiffer cmsg = CMSG_FIRSTHDR(&msg);
22182657471SMarkus Pfeiffer if (cmsg == NULL) {
22282657471SMarkus Pfeiffer sysv_print_err("no message header\n");
22382657471SMarkus Pfeiffer return (-1);
22482657471SMarkus Pfeiffer }
22582657471SMarkus Pfeiffer if (cmsg->cmsg_type != SCM_RIGHTS)
22682657471SMarkus Pfeiffer sysv_print_err("expected type %d got %d\n",
22782657471SMarkus Pfeiffer SCM_RIGHTS, cmsg->cmsg_type);
22882657471SMarkus Pfeiffer
22982657471SMarkus Pfeiffer fd = (*(int *)CMSG_DATA(cmsg));
23082657471SMarkus Pfeiffer return (fd);
23182657471SMarkus Pfeiffer } else {
23282657471SMarkus Pfeiffer errno = result;
23382657471SMarkus Pfeiffer return (-1);
23482657471SMarkus Pfeiffer }
23582657471SMarkus Pfeiffer }
23682657471SMarkus Pfeiffer
23782657471SMarkus Pfeiffer static void
close_fds(int * fds,int num_fds)238*ff86f401SSascha Wildner close_fds(int *fds, int num_fds)
239*ff86f401SSascha Wildner {
24082657471SMarkus Pfeiffer int i;
24182657471SMarkus Pfeiffer
24282657471SMarkus Pfeiffer for (i=0; i < num_fds; i++)
24382657471SMarkus Pfeiffer close(fds[i]);
24482657471SMarkus Pfeiffer }
24582657471SMarkus Pfeiffer
24682657471SMarkus Pfeiffer /* Send with the message, credentials too. */
24782657471SMarkus Pfeiffer int
send_msg_with_cred(int sock,char * buffer,size_t size)248*ff86f401SSascha Wildner send_msg_with_cred(int sock, char *buffer, size_t size)
249*ff86f401SSascha Wildner {
25082657471SMarkus Pfeiffer struct msghdr msg;
25182657471SMarkus Pfeiffer struct iovec vec;
25282657471SMarkus Pfeiffer ssize_t n;
25382657471SMarkus Pfeiffer
25482657471SMarkus Pfeiffer struct {
25582657471SMarkus Pfeiffer struct cmsghdr hdr;
25682657471SMarkus Pfeiffer char cred[CMSG_SPACE(sizeof(struct cmsgcred))];
25782657471SMarkus Pfeiffer } cmsg;
25882657471SMarkus Pfeiffer
25982657471SMarkus Pfeiffer memset(&cmsg, 0, sizeof(cmsg));
26082657471SMarkus Pfeiffer cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
26182657471SMarkus Pfeiffer cmsg.hdr.cmsg_level = SOL_SOCKET;
26282657471SMarkus Pfeiffer cmsg.hdr.cmsg_type = SCM_CREDS;
26382657471SMarkus Pfeiffer
26482657471SMarkus Pfeiffer memset(&msg, 0, sizeof(struct msghdr));
26582657471SMarkus Pfeiffer msg.msg_iov = &vec;
26682657471SMarkus Pfeiffer msg.msg_iovlen = 1;
26782657471SMarkus Pfeiffer msg.msg_control = (caddr_t)&cmsg;
26882657471SMarkus Pfeiffer msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
26982657471SMarkus Pfeiffer
27082657471SMarkus Pfeiffer vec.iov_base = buffer;
27182657471SMarkus Pfeiffer vec.iov_len = size;
27282657471SMarkus Pfeiffer
27382657471SMarkus Pfeiffer if ((n = sendmsg(sock, &msg, 0)) == -1) {
27482657471SMarkus Pfeiffer sysv_print_err("sendmsg on fd %d\n", sock);
27582657471SMarkus Pfeiffer return (-1);
27682657471SMarkus Pfeiffer }
27782657471SMarkus Pfeiffer
27882657471SMarkus Pfeiffer return (0);
27982657471SMarkus Pfeiffer }
28082657471SMarkus Pfeiffer
28182657471SMarkus Pfeiffer /* Receive a message and the credentials of the sender. */
28282657471SMarkus Pfeiffer int
receive_msg_with_cred(int sock,char * buffer,size_t size,struct cmsgcred * cred)28382657471SMarkus Pfeiffer receive_msg_with_cred(int sock, char *buffer, size_t size,
284*ff86f401SSascha Wildner struct cmsgcred *cred)
285*ff86f401SSascha Wildner {
286381fa6daSSascha Wildner struct msghdr msg = { .msg_name = NULL };
28782657471SMarkus Pfeiffer struct iovec vec;
28882657471SMarkus Pfeiffer ssize_t n;
28982657471SMarkus Pfeiffer int result;
29082657471SMarkus Pfeiffer struct cmsghdr *cmp;
29182657471SMarkus Pfeiffer struct {
29282657471SMarkus Pfeiffer struct cmsghdr hdr;
29382657471SMarkus Pfeiffer char cred[CMSG_SPACE(sizeof(struct cmsgcred))];
29482657471SMarkus Pfeiffer } cmsg;
29582657471SMarkus Pfeiffer
29682657471SMarkus Pfeiffer memset(&msg, 0, sizeof(msg));
29782657471SMarkus Pfeiffer vec.iov_base = buffer;
29882657471SMarkus Pfeiffer vec.iov_len = size;
29982657471SMarkus Pfeiffer msg.msg_iov = &vec;
30082657471SMarkus Pfeiffer msg.msg_iovlen = 1;
30182657471SMarkus Pfeiffer
30282657471SMarkus Pfeiffer msg.msg_control = &cmsg;
30382657471SMarkus Pfeiffer msg.msg_controllen = sizeof(cmsg);
30482657471SMarkus Pfeiffer
30582657471SMarkus Pfeiffer do {
30682657471SMarkus Pfeiffer n = recvmsg(sock, &msg, 0);
30782657471SMarkus Pfeiffer } while (n < 0 && errno == EINTR);
30882657471SMarkus Pfeiffer
30982657471SMarkus Pfeiffer if (n < 0) {
31082657471SMarkus Pfeiffer sysv_print_err("recvmsg on fd %d\n", sock);
31182657471SMarkus Pfeiffer return (-1);
31282657471SMarkus Pfeiffer }
31382657471SMarkus Pfeiffer
31482657471SMarkus Pfeiffer if (n == 0) {
31582657471SMarkus Pfeiffer return (-1);
31682657471SMarkus Pfeiffer }
31782657471SMarkus Pfeiffer
31882657471SMarkus Pfeiffer result = -1;
31982657471SMarkus Pfeiffer cmp = CMSG_FIRSTHDR(&msg);
32082657471SMarkus Pfeiffer
32182657471SMarkus Pfeiffer while(cmp != NULL) {
32282657471SMarkus Pfeiffer if (cmp->cmsg_level == SOL_SOCKET
32382657471SMarkus Pfeiffer && cmp->cmsg_type == SCM_CREDS) {
32482657471SMarkus Pfeiffer if (cred)
32582657471SMarkus Pfeiffer memcpy(cred, CMSG_DATA(cmp), sizeof(*cred));
32682657471SMarkus Pfeiffer result = n;
32782657471SMarkus Pfeiffer } else if (cmp->cmsg_level == SOL_SOCKET
32882657471SMarkus Pfeiffer && cmp->cmsg_type == SCM_RIGHTS) {
32982657471SMarkus Pfeiffer close_fds((int *) CMSG_DATA(cmp),
33082657471SMarkus Pfeiffer (cmp->cmsg_len - CMSG_LEN(0))
33182657471SMarkus Pfeiffer / sizeof(int));
33282657471SMarkus Pfeiffer }
33382657471SMarkus Pfeiffer cmp = CMSG_NXTHDR(&msg, cmp);
33482657471SMarkus Pfeiffer }
33582657471SMarkus Pfeiffer
33682657471SMarkus Pfeiffer return (result);
33782657471SMarkus Pfeiffer }
338