1 /*- 2 * Copyright (c) 2013 The FreeBSD Foundation 3 * Copyright (c) 2013 Mariusz Zaborski <oshogbo@FreeBSD.org> 4 * All rights reserved. 5 * 6 * This software was developed by Pawel Jakub Dawidek under sponsorship from 7 * the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/types.h> 35 #include <sys/socket.h> 36 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <stdbool.h> 40 #include <stdint.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #ifdef HAVE_PJDLOG 46 #include <pjdlog.h> 47 #endif 48 49 #include "common_impl.h" 50 #include "msgio.h" 51 52 #ifndef HAVE_PJDLOG 53 #include <assert.h> 54 #define PJDLOG_ASSERT(...) assert(__VA_ARGS__) 55 #define PJDLOG_RASSERT(expr, ...) assert(expr) 56 #define PJDLOG_ABORT(...) abort() 57 #endif 58 59 static int 60 msghdr_add_fd(struct cmsghdr *cmsg, int fd) 61 { 62 63 PJDLOG_ASSERT(fd >= 0); 64 65 if (!fd_is_valid(fd)) { 66 errno = EBADF; 67 return (-1); 68 } 69 70 cmsg->cmsg_level = SOL_SOCKET; 71 cmsg->cmsg_type = SCM_RIGHTS; 72 cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); 73 bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd)); 74 75 return (0); 76 } 77 78 static int 79 msghdr_get_fd(struct cmsghdr *cmsg) 80 { 81 int fd; 82 83 if (cmsg == NULL || cmsg->cmsg_level != SOL_SOCKET || 84 cmsg->cmsg_type != SCM_RIGHTS || 85 cmsg->cmsg_len != CMSG_LEN(sizeof(fd))) { 86 errno = EINVAL; 87 return (-1); 88 } 89 90 bcopy(CMSG_DATA(cmsg), &fd, sizeof(fd)); 91 #ifndef MSG_CMSG_CLOEXEC 92 /* 93 * If the MSG_CMSG_CLOEXEC flag is not available we cannot set the 94 * close-on-exec flag atomically, but we still want to set it for 95 * consistency. 96 */ 97 (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 98 #endif 99 100 return (fd); 101 } 102 103 static void 104 fd_wait(int fd, bool doread) 105 { 106 fd_set fds; 107 108 PJDLOG_ASSERT(fd >= 0); 109 110 FD_ZERO(&fds); 111 FD_SET(fd, &fds); 112 (void)select(fd + 1, doread ? &fds : NULL, doread ? NULL : &fds, 113 NULL, NULL); 114 } 115 116 static int 117 msg_recv(int sock, struct msghdr *msg) 118 { 119 int flags; 120 121 PJDLOG_ASSERT(sock >= 0); 122 123 #ifdef MSG_CMSG_CLOEXEC 124 flags = MSG_CMSG_CLOEXEC; 125 #else 126 flags = 0; 127 #endif 128 129 for (;;) { 130 fd_wait(sock, true); 131 if (recvmsg(sock, msg, flags) == -1) { 132 if (errno == EINTR) 133 continue; 134 return (-1); 135 } 136 break; 137 } 138 139 return (0); 140 } 141 142 static int 143 msg_send(int sock, const struct msghdr *msg) 144 { 145 146 PJDLOG_ASSERT(sock >= 0); 147 148 for (;;) { 149 fd_wait(sock, false); 150 if (sendmsg(sock, msg, 0) == -1) { 151 if (errno == EINTR) 152 continue; 153 return (-1); 154 } 155 break; 156 } 157 158 return (0); 159 } 160 161 int 162 cred_send(int sock) 163 { 164 unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))]; 165 struct msghdr msg; 166 struct cmsghdr *cmsg; 167 struct iovec iov; 168 uint8_t dummy; 169 170 bzero(credbuf, sizeof(credbuf)); 171 bzero(&msg, sizeof(msg)); 172 bzero(&iov, sizeof(iov)); 173 174 /* 175 * XXX: We send one byte along with the control message, because 176 * setting msg_iov to NULL only works if this is the first 177 * packet send over the socket. Once we send some data we 178 * won't be able to send credentials anymore. This is most 179 * likely a kernel bug. 180 */ 181 dummy = 0; 182 iov.iov_base = &dummy; 183 iov.iov_len = sizeof(dummy); 184 185 msg.msg_iov = &iov; 186 msg.msg_iovlen = 1; 187 msg.msg_control = credbuf; 188 msg.msg_controllen = sizeof(credbuf); 189 190 cmsg = CMSG_FIRSTHDR(&msg); 191 cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred)); 192 cmsg->cmsg_level = SOL_SOCKET; 193 cmsg->cmsg_type = SCM_CREDS; 194 195 if (msg_send(sock, &msg) == -1) 196 return (-1); 197 198 return (0); 199 } 200 201 int 202 cred_recv(int sock, struct cmsgcred *cred) 203 { 204 unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))]; 205 struct msghdr msg; 206 struct cmsghdr *cmsg; 207 struct iovec iov; 208 uint8_t dummy; 209 210 bzero(credbuf, sizeof(credbuf)); 211 bzero(&msg, sizeof(msg)); 212 bzero(&iov, sizeof(iov)); 213 214 iov.iov_base = &dummy; 215 iov.iov_len = sizeof(dummy); 216 217 msg.msg_iov = &iov; 218 msg.msg_iovlen = 1; 219 msg.msg_control = credbuf; 220 msg.msg_controllen = sizeof(credbuf); 221 222 if (msg_recv(sock, &msg) == -1) 223 return (-1); 224 225 cmsg = CMSG_FIRSTHDR(&msg); 226 if (cmsg == NULL || 227 cmsg->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred)) || 228 cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDS) { 229 errno = EINVAL; 230 return (-1); 231 } 232 bcopy(CMSG_DATA(cmsg), cred, sizeof(*cred)); 233 234 return (0); 235 } 236 237 int 238 fd_send(int sock, const int *fds, size_t nfds) 239 { 240 struct msghdr msg; 241 struct cmsghdr *cmsg; 242 unsigned int i; 243 int serrno, ret; 244 245 if (nfds == 0 || fds == NULL) { 246 errno = EINVAL; 247 return (-1); 248 } 249 250 bzero(&msg, sizeof(msg)); 251 msg.msg_iov = NULL; 252 msg.msg_iovlen = 0; 253 msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int)); 254 msg.msg_control = calloc(1, msg.msg_controllen); 255 if (msg.msg_control == NULL) 256 return (-1); 257 258 ret = -1; 259 260 for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL; 261 i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) { 262 if (msghdr_add_fd(cmsg, fds[i]) == -1) 263 goto end; 264 } 265 266 if (msg_send(sock, &msg) == -1) 267 goto end; 268 269 ret = 0; 270 end: 271 serrno = errno; 272 free(msg.msg_control); 273 errno = serrno; 274 return (ret); 275 } 276 277 int 278 fd_recv(int sock, int *fds, size_t nfds) 279 { 280 struct msghdr msg; 281 struct cmsghdr *cmsg; 282 unsigned int i; 283 int serrno, ret; 284 285 if (nfds == 0 || fds == NULL) { 286 errno = EINVAL; 287 return (-1); 288 } 289 290 bzero(&msg, sizeof(msg)); 291 msg.msg_iov = NULL; 292 msg.msg_iovlen = 0; 293 msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int)); 294 msg.msg_control = calloc(1, msg.msg_controllen); 295 if (msg.msg_control == NULL) 296 return (-1); 297 298 ret = -1; 299 300 if (msg_recv(sock, &msg) == -1) 301 goto end; 302 303 for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL; 304 i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) { 305 fds[i] = msghdr_get_fd(cmsg); 306 if (fds[i] < 0) 307 break; 308 } 309 310 if (cmsg != NULL || i < nfds) { 311 int fd; 312 313 /* 314 * We need to close all received descriptors, even if we have 315 * different control message (eg. SCM_CREDS) in between. 316 */ 317 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 318 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 319 fd = msghdr_get_fd(cmsg); 320 if (fd >= 0) 321 close(fd); 322 } 323 errno = EINVAL; 324 goto end; 325 } 326 327 ret = 0; 328 end: 329 serrno = errno; 330 free(msg.msg_control); 331 errno = serrno; 332 return (ret); 333 } 334 335 int 336 buf_send(int sock, void *buf, size_t size) 337 { 338 ssize_t done; 339 unsigned char *ptr; 340 341 PJDLOG_ASSERT(sock >= 0); 342 PJDLOG_ASSERT(size > 0); 343 PJDLOG_ASSERT(buf != NULL); 344 345 ptr = buf; 346 do { 347 fd_wait(sock, false); 348 done = send(sock, ptr, size, 0); 349 if (done == -1) { 350 if (errno == EINTR) 351 continue; 352 return (-1); 353 } else if (done == 0) { 354 errno = ENOTCONN; 355 return (-1); 356 } 357 size -= done; 358 ptr += done; 359 } while (size > 0); 360 361 return (0); 362 } 363 364 int 365 buf_recv(int sock, void *buf, size_t size) 366 { 367 ssize_t done; 368 unsigned char *ptr; 369 370 PJDLOG_ASSERT(sock >= 0); 371 PJDLOG_ASSERT(buf != NULL); 372 373 ptr = buf; 374 while (size > 0) { 375 fd_wait(sock, true); 376 done = recv(sock, ptr, size, 0); 377 if (done == -1) { 378 if (errno == EINTR) 379 continue; 380 return (-1); 381 } else if (done == 0) { 382 errno = ENOTCONN; 383 return (-1); 384 } 385 size -= done; 386 ptr += done; 387 } 388 389 return (0); 390 } 391