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 int 117 msg_peek(int sock, void *buf, size_t size) 118 { 119 ssize_t done; 120 121 PJDLOG_ASSERT(sock >= 0); 122 PJDLOG_ASSERT(size > 0); 123 124 do { 125 fd_wait(sock, true); 126 done = recv(sock, buf, size, MSG_PEEK | MSG_WAITALL); 127 if (done == -1) { 128 if (errno == EAGAIN || errno == EINTR) 129 continue; 130 return (-1); 131 } else if (done == 0) { 132 errno = ENOTCONN; 133 return (-1); 134 } 135 } while (done != (ssize_t)size); 136 137 return (0); 138 } 139 140 static int 141 msg_recv(int sock, struct msghdr *msg) 142 { 143 int flags; 144 145 PJDLOG_ASSERT(sock >= 0); 146 147 #ifdef MSG_CMSG_CLOEXEC 148 flags = MSG_CMSG_CLOEXEC; 149 #else 150 flags = 0; 151 #endif 152 153 for (;;) { 154 fd_wait(sock, true); 155 if (recvmsg(sock, msg, flags) == -1) { 156 if (errno == EINTR) 157 continue; 158 return (-1); 159 } 160 break; 161 } 162 163 return (0); 164 } 165 166 static int 167 msg_send(int sock, const struct msghdr *msg) 168 { 169 170 PJDLOG_ASSERT(sock >= 0); 171 172 for (;;) { 173 fd_wait(sock, false); 174 if (sendmsg(sock, msg, 0) == -1) { 175 if (errno == EINTR) 176 continue; 177 return (-1); 178 } 179 break; 180 } 181 182 return (0); 183 } 184 185 int 186 cred_send(int sock) 187 { 188 unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))]; 189 struct msghdr msg; 190 struct cmsghdr *cmsg; 191 struct iovec iov; 192 uint8_t dummy; 193 194 bzero(credbuf, sizeof(credbuf)); 195 bzero(&msg, sizeof(msg)); 196 bzero(&iov, sizeof(iov)); 197 198 /* 199 * XXX: We send one byte along with the control message, because 200 * setting msg_iov to NULL only works if this is the first 201 * packet send over the socket. Once we send some data we 202 * won't be able to send credentials anymore. This is most 203 * likely a kernel bug. 204 */ 205 dummy = 0; 206 iov.iov_base = &dummy; 207 iov.iov_len = sizeof(dummy); 208 209 msg.msg_iov = &iov; 210 msg.msg_iovlen = 1; 211 msg.msg_control = credbuf; 212 msg.msg_controllen = sizeof(credbuf); 213 214 cmsg = CMSG_FIRSTHDR(&msg); 215 cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred)); 216 cmsg->cmsg_level = SOL_SOCKET; 217 cmsg->cmsg_type = SCM_CREDS; 218 219 if (msg_send(sock, &msg) == -1) 220 return (-1); 221 222 return (0); 223 } 224 225 int 226 cred_recv(int sock, struct cmsgcred *cred) 227 { 228 unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))]; 229 struct msghdr msg; 230 struct cmsghdr *cmsg; 231 struct iovec iov; 232 uint8_t dummy; 233 234 bzero(credbuf, sizeof(credbuf)); 235 bzero(&msg, sizeof(msg)); 236 bzero(&iov, sizeof(iov)); 237 238 iov.iov_base = &dummy; 239 iov.iov_len = sizeof(dummy); 240 241 msg.msg_iov = &iov; 242 msg.msg_iovlen = 1; 243 msg.msg_control = credbuf; 244 msg.msg_controllen = sizeof(credbuf); 245 246 if (msg_recv(sock, &msg) == -1) 247 return (-1); 248 249 cmsg = CMSG_FIRSTHDR(&msg); 250 if (cmsg == NULL || 251 cmsg->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred)) || 252 cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDS) { 253 errno = EINVAL; 254 return (-1); 255 } 256 bcopy(CMSG_DATA(cmsg), cred, sizeof(*cred)); 257 258 return (0); 259 } 260 261 int 262 fd_send(int sock, const int *fds, size_t nfds) 263 { 264 struct msghdr msg; 265 struct cmsghdr *cmsg; 266 unsigned int i; 267 int serrno, ret; 268 269 if (nfds == 0 || fds == NULL) { 270 errno = EINVAL; 271 return (-1); 272 } 273 274 bzero(&msg, sizeof(msg)); 275 msg.msg_iov = NULL; 276 msg.msg_iovlen = 0; 277 msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int)); 278 msg.msg_control = calloc(1, msg.msg_controllen); 279 if (msg.msg_control == NULL) 280 return (-1); 281 282 ret = -1; 283 284 for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL; 285 i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) { 286 if (msghdr_add_fd(cmsg, fds[i]) == -1) 287 goto end; 288 } 289 290 if (msg_send(sock, &msg) == -1) 291 goto end; 292 293 ret = 0; 294 end: 295 serrno = errno; 296 free(msg.msg_control); 297 errno = serrno; 298 return (ret); 299 } 300 301 int 302 fd_recv(int sock, int *fds, size_t nfds) 303 { 304 struct msghdr msg; 305 struct cmsghdr *cmsg; 306 unsigned int i; 307 int serrno, ret; 308 309 if (nfds == 0 || fds == NULL) { 310 errno = EINVAL; 311 return (-1); 312 } 313 314 bzero(&msg, sizeof(msg)); 315 msg.msg_iov = NULL; 316 msg.msg_iovlen = 0; 317 msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int)); 318 msg.msg_control = calloc(1, msg.msg_controllen); 319 if (msg.msg_control == NULL) 320 return (-1); 321 322 ret = -1; 323 324 if (msg_recv(sock, &msg) == -1) 325 goto end; 326 327 for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL; 328 i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) { 329 fds[i] = msghdr_get_fd(cmsg); 330 if (fds[i] < 0) 331 break; 332 } 333 334 if (cmsg != NULL || i < nfds) { 335 int fd; 336 337 /* 338 * We need to close all received descriptors, even if we have 339 * different control message (eg. SCM_CREDS) in between. 340 */ 341 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 342 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 343 fd = msghdr_get_fd(cmsg); 344 if (fd >= 0) 345 close(fd); 346 } 347 errno = EINVAL; 348 goto end; 349 } 350 351 ret = 0; 352 end: 353 serrno = errno; 354 free(msg.msg_control); 355 errno = serrno; 356 return (ret); 357 } 358 359 int 360 buf_send(int sock, void *buf, size_t size) 361 { 362 ssize_t done; 363 unsigned char *ptr; 364 365 ptr = buf; 366 do { 367 fd_wait(sock, false); 368 done = send(sock, ptr, size, 0); 369 if (done == -1) { 370 if (errno == EINTR) 371 continue; 372 return (-1); 373 } else if (done == 0) { 374 errno = ENOTCONN; 375 return (-1); 376 } 377 size -= done; 378 ptr += done; 379 } while (size > 0); 380 381 return (0); 382 } 383 384 int 385 buf_recv(int sock, void *buf, size_t size) 386 { 387 ssize_t done; 388 unsigned char *ptr; 389 390 ptr = buf; 391 do { 392 fd_wait(sock, true); 393 done = recv(sock, ptr, size, 0); 394 if (done == -1) { 395 if (errno == EINTR) 396 continue; 397 return (-1); 398 } else if (done == 0) { 399 errno = ENOTCONN; 400 return (-1); 401 } 402 size -= done; 403 ptr += done; 404 } while (size > 0); 405 406 return (0); 407 } 408