1 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
2 
3 /*
4    fdpass.c - File descriptor passing between processes via UNIX sockets
5 
6    This isn't fully portable, but pretty much all UNIXes nowadays should
7    support this. If you're having runtime problems with fd_read(), check the
8    end of fd_read() and play with the if condition. If you're having problems
9    with fd_send(), try defining BUGGY_CMSG_MACROS.
10 
11    If this file doesn't compile at all, you should check if this is supported
12    in your system at all. It may require some extra #define to enable it.
13    If not, you're pretty much out of luck. Cygwin didn't last I checked.
14 */
15 
16 #define _XPG4_2
17 
18 #if defined(irix) || defined (__irix__) || defined(sgi) || defined (__sgi__)
19 #  define _XOPEN_SOURCE 4 /* for IRIX */
20 #endif
21 
22 #if !defined(_AIX) && !defined(_XOPEN_SOURCE_EXTENDED)
23 #  define _XOPEN_SOURCE_EXTENDED /* for Tru64, breaks AIX */
24 #endif
25 
26 #ifdef HAVE_CONFIG_H
27 #  include "lib.h"
28 #else
29 #  define i_assert(x)
30 #endif
31 
32 #include <string.h>
33 #include <limits.h>
34 #include <sys/types.h>
35 
36 #include <sys/socket.h>
37 #include <sys/un.h>
38 #include <sys/uio.h>
39 
40 #include "fdpass.h"
41 
42 #ifndef HAVE_CONFIG_H
43 struct const_iovec {
44 	const void *iov_base;
45 	size_t iov_len;
46 };
47 #endif
48 
49 /* RFC 2292 defines CMSG_*() macros, but some operating systems don't have them
50    so we'll define our own if they don't exist.
51 
52    CMSG_LEN(data) is used to calculate size of sizeof(struct cmsghdr) +
53    sizeof(data) and padding between them.
54 
55    CMSG_SPACE(data) also calculates the padding needed after the data, in case
56    multiple objects are sent.
57 
58    cmsghdr contains cmsg_len field and two integers. cmsg_len is sometimes
59    defined as sockaddr_t and sometimes size_t, so it can be either 32bit or
60    64bit. This padding is added by compiler in sizeof(struct cmsghdr).
61 
62    Padding required by CMSG_DATA() can vary. Usually it wants size_t or 32bit.
63    With Solaris it's in _CMSG_DATA_ALIGNMENT (32bit), we assume others want
64    size_t.
65 
66    We don't really need CMSG_SPACE() to be exactly correct, because currently
67    we send only one object at a time. But anyway I'm trying to keep that
68    correct in case it's sometimes needed..
69 */
70 
71 #ifdef BUGGY_CMSG_MACROS
72 /* Some OSes have broken CMSG macros in 64bit systems. The macros use 64bit
73    alignment while kernel uses 32bit alignment. */
74 #  undef CMSG_SPACE
75 #  undef CMSG_LEN
76 #  undef CMSG_DATA
77 #  define CMSG_DATA(cmsg) ((char *)((cmsg) + 1))
78 #  define _CMSG_DATA_ALIGNMENT 4
79 #  define _CMSG_HDR_ALIGNMENT 4
80 #endif
81 
82 #ifndef CMSG_SPACE
83 #  define MY_ALIGN(len, align) \
84 	(((len) + align - 1) & ~(align - 1))
85 
86 /* Alignment between cmsghdr and data */
87 #  ifndef _CMSG_DATA_ALIGNMENT
88 #    define _CMSG_DATA_ALIGNMENT sizeof(size_t)
89 #  endif
90 /* Alignment between data and next cmsghdr */
91 #  ifndef _CMSG_HDR_ALIGNMENT
92 #    define _CMSG_HDR_ALIGNMENT sizeof(size_t)
93 #  endif
94 
95 #  define CMSG_SPACE(len) \
96 	(MY_ALIGN(sizeof(struct cmsghdr), _CMSG_DATA_ALIGNMENT) + \
97 	 MY_ALIGN(len, _CMSG_HDR_ALIGNMENT))
98 #  define CMSG_LEN(len) \
99 	(MY_ALIGN(sizeof(struct cmsghdr), _CMSG_DATA_ALIGNMENT) + (len))
100 #endif
101 
102 #ifdef SCM_RIGHTS
103 
fd_send(int handle,int send_fd,const void * data,size_t size)104 ssize_t fd_send(int handle, int send_fd, const void *data, size_t size)
105 {
106         struct msghdr msg;
107         struct const_iovec iov;
108         struct cmsghdr *cmsg;
109 	char buf[CMSG_SPACE(sizeof(int))];
110 
111 	/* at least one byte is required to be sent with fd passing */
112 	i_assert(size > 0 && size < INT_MAX);
113 
114 	memset(&msg, 0, sizeof(struct msghdr));
115 
116         iov.iov_base = data;
117         iov.iov_len = size;
118 
119         msg.msg_iov = (void *)&iov;
120 	msg.msg_iovlen = 1;
121 
122 	if (send_fd != -1) {
123 		/* set the control and controllen before CMSG_FIRSTHDR(). */
124 		memset(buf, 0, sizeof(buf));
125 		msg.msg_control = buf;
126 		msg.msg_controllen = sizeof(buf);
127 
128 		cmsg = CMSG_FIRSTHDR(&msg);
129 		cmsg->cmsg_level = SOL_SOCKET;
130 		cmsg->cmsg_type = SCM_RIGHTS;
131 		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
132 		memcpy(CMSG_DATA(cmsg), &send_fd, sizeof(send_fd));
133 
134 		/* set the real length we want to use. Do it after all is
135 		   set just in case CMSG macros required the extra padding
136 		   in the end. */
137 		msg.msg_controllen = cmsg->cmsg_len;
138 	}
139 
140 	return sendmsg(handle, &msg, 0);
141 }
142 
143 #ifdef LINUX20
144 /* Linux 2.0.x doesn't set any cmsg fields. Note that this might make some
145    attacks possible so don't do it unless you really have to. */
146 #  define CHECK_CMSG(cmsg) ((cmsg) != NULL)
147 #else
148 #  define CHECK_CMSG(cmsg) \
149 	((cmsg) != NULL && \
150 	 (size_t)(cmsg)->cmsg_len >= (size_t)CMSG_LEN(sizeof(int)) && \
151 	 (cmsg)->cmsg_level == SOL_SOCKET && (cmsg)->cmsg_type == SCM_RIGHTS)
152 #endif
153 
fd_read(int handle,void * data,size_t size,int * fd)154 ssize_t fd_read(int handle, void *data, size_t size, int *fd)
155 {
156 	struct msghdr msg;
157 	struct iovec iov;
158 	struct cmsghdr *cmsg;
159 	ssize_t ret;
160 	char buf[CMSG_SPACE(sizeof(int))];
161 
162 	i_assert(size > 0 && size < INT_MAX);
163 
164 	memset(&msg, 0, sizeof (struct msghdr));
165 
166 	iov.iov_base = data;
167 	iov.iov_len = size;
168 
169 	msg.msg_iov = &iov;
170 	msg.msg_iovlen = 1;
171 
172 	memset(buf, 0, sizeof(buf));
173 	msg.msg_control = buf;
174 	msg.msg_controllen = sizeof(buf);
175 
176 	ret = recvmsg(handle, &msg, 0);
177 	if (ret <= 0) {
178 		*fd = -1;
179 		return ret;
180 	}
181 
182 	/* at least one byte transferred - we should have the fd now.
183 	   do extra checks to make sure it really is an fd that is being
184 	   transferred to avoid potential DoS conditions. some systems don't
185 	   set all these values correctly however so CHECK_CMSG() is somewhat
186 	   system dependent */
187 	cmsg = CMSG_FIRSTHDR(&msg);
188 	if (!CHECK_CMSG(cmsg))
189 		*fd = -1;
190 	else
191 		memcpy(fd, CMSG_DATA(cmsg), sizeof(*fd));
192 	return ret;
193 }
194 
195 #else
196 #  ifdef __GNUC__
197 #    warning SCM_RIGHTS not supported, privilege separation not possible
198 #  endif
fd_send(int handle ATTR_UNUSED,int send_fd ATTR_UNUSED,const void * data ATTR_UNUSED,size_t size ATTR_UNUSED)199 ssize_t fd_send(int handle ATTR_UNUSED, int send_fd ATTR_UNUSED,
200 		const void *data ATTR_UNUSED, size_t size ATTR_UNUSED)
201 {
202 	errno = ENOSYS;
203 	return -1;
204 }
205 
fd_read(int handle ATTR_UNUSED,void * data ATTR_UNUSED,size_t size ATTR_UNUSED,int * fd ATTR_UNUSED)206 ssize_t fd_read(int handle ATTR_UNUSED, void *data ATTR_UNUSED,
207 		size_t size ATTR_UNUSED, int *fd ATTR_UNUSED)
208 {
209 	errno = ENOSYS;
210 	return -1;
211 }
212 #endif
213