1292023Srodrigc/* $OpenBSD: imsg.c,v 1.13 2015/12/09 11:54:12 tb Exp $ */ 2290375Srodrigc 3290375Srodrigc/* 4290375Srodrigc * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 5290375Srodrigc * 6290375Srodrigc * Permission to use, copy, modify, and distribute this software for any 7290375Srodrigc * purpose with or without fee is hereby granted, provided that the above 8290375Srodrigc * copyright notice and this permission notice appear in all copies. 9290375Srodrigc * 10290375Srodrigc * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11290375Srodrigc * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12290375Srodrigc * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13290375Srodrigc * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14290375Srodrigc * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15290375Srodrigc * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16290375Srodrigc * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17290375Srodrigc * 18290375Srodrigc * $FreeBSD$ 19290375Srodrigc */ 20290375Srodrigc 21290375Srodrigc#include <sys/types.h> 22290375Srodrigc#include <sys/queue.h> 23290375Srodrigc#include <sys/socket.h> 24290375Srodrigc#include <sys/uio.h> 25290375Srodrigc 26290375Srodrigc#include <errno.h> 27290375Srodrigc#include <stdlib.h> 28290375Srodrigc#include <string.h> 29290375Srodrigc#include <unistd.h> 30290375Srodrigc 31290375Srodrigc#include "imsg.h" 32290375Srodrigc 33290375Srodrigcint imsg_fd_overhead = 0; 34290375Srodrigc 35290375Srodrigcint imsg_get_fd(struct imsgbuf *); 36290375Srodrigc 37290375Srodrigcvoid 38290375Srodrigcimsg_init(struct imsgbuf *ibuf, int fd) 39290375Srodrigc{ 40290375Srodrigc msgbuf_init(&ibuf->w); 41290375Srodrigc memset(&ibuf->r, 0, sizeof(ibuf->r)); 42290375Srodrigc ibuf->fd = fd; 43290375Srodrigc ibuf->w.fd = fd; 44290375Srodrigc ibuf->pid = getpid(); 45290375Srodrigc TAILQ_INIT(&ibuf->fds); 46290375Srodrigc} 47290375Srodrigc 48290375Srodrigcssize_t 49290375Srodrigcimsg_read(struct imsgbuf *ibuf) 50290375Srodrigc{ 51290375Srodrigc struct msghdr msg; 52290375Srodrigc struct cmsghdr *cmsg; 53290375Srodrigc union { 54290375Srodrigc struct cmsghdr hdr; 55290375Srodrigc char buf[CMSG_SPACE(sizeof(int) * 1)]; 56290375Srodrigc } cmsgbuf; 57290375Srodrigc struct iovec iov; 58290375Srodrigc ssize_t n = -1; 59290375Srodrigc int fd; 60290375Srodrigc struct imsg_fd *ifd; 61290375Srodrigc 62290375Srodrigc memset(&msg, 0, sizeof(msg)); 63290375Srodrigc memset(&cmsgbuf, 0, sizeof(cmsgbuf)); 64290375Srodrigc 65290375Srodrigc iov.iov_base = ibuf->r.buf + ibuf->r.wpos; 66290375Srodrigc iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos; 67290375Srodrigc msg.msg_iov = &iov; 68290375Srodrigc msg.msg_iovlen = 1; 69290375Srodrigc msg.msg_control = &cmsgbuf.buf; 70290375Srodrigc msg.msg_controllen = sizeof(cmsgbuf.buf); 71290375Srodrigc 72290375Srodrigc if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) 73290375Srodrigc return (-1); 74290375Srodrigc 75290375Srodrigcagain: 76290375Srodrigc if (getdtablecount() + imsg_fd_overhead + 77292023Srodrigc (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int)) 78290375Srodrigc >= getdtablesize()) { 79290375Srodrigc errno = EAGAIN; 80290375Srodrigc free(ifd); 81290375Srodrigc return (-1); 82290375Srodrigc } 83290375Srodrigc 84290375Srodrigc if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { 85292022Srodrigc if (errno == EINTR) 86292022Srodrigc goto again; 87292022Srodrigc goto fail; 88290375Srodrigc } 89290375Srodrigc 90290375Srodrigc ibuf->r.wpos += n; 91290375Srodrigc 92290375Srodrigc for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 93290375Srodrigc cmsg = CMSG_NXTHDR(&msg, cmsg)) { 94290375Srodrigc if (cmsg->cmsg_level == SOL_SOCKET && 95290375Srodrigc cmsg->cmsg_type == SCM_RIGHTS) { 96290375Srodrigc int i; 97290375Srodrigc int j; 98290375Srodrigc 99290375Srodrigc /* 100290375Srodrigc * We only accept one file descriptor. Due to C 101290375Srodrigc * padding rules, our control buffer might contain 102290375Srodrigc * more than one fd, and we must close them. 103290375Srodrigc */ 104290375Srodrigc j = ((char *)cmsg + cmsg->cmsg_len - 105290375Srodrigc (char *)CMSG_DATA(cmsg)) / sizeof(int); 106290375Srodrigc for (i = 0; i < j; i++) { 107290375Srodrigc fd = ((int *)CMSG_DATA(cmsg))[i]; 108290375Srodrigc if (ifd != NULL) { 109290375Srodrigc ifd->fd = fd; 110290375Srodrigc TAILQ_INSERT_TAIL(&ibuf->fds, ifd, 111290375Srodrigc entry); 112290375Srodrigc ifd = NULL; 113290375Srodrigc } else 114290375Srodrigc close(fd); 115290375Srodrigc } 116290375Srodrigc } 117290375Srodrigc /* we do not handle other ctl data level */ 118290375Srodrigc } 119290375Srodrigc 120290375Srodrigcfail: 121292021Srodrigc free(ifd); 122290375Srodrigc return (n); 123290375Srodrigc} 124290375Srodrigc 125290375Srodrigcssize_t 126290375Srodrigcimsg_get(struct imsgbuf *ibuf, struct imsg *imsg) 127290375Srodrigc{ 128290375Srodrigc size_t av, left, datalen; 129290375Srodrigc 130290375Srodrigc av = ibuf->r.wpos; 131290375Srodrigc 132290375Srodrigc if (IMSG_HEADER_SIZE > av) 133290375Srodrigc return (0); 134290375Srodrigc 135290375Srodrigc memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr)); 136290375Srodrigc if (imsg->hdr.len < IMSG_HEADER_SIZE || 137290375Srodrigc imsg->hdr.len > MAX_IMSGSIZE) { 138290375Srodrigc errno = ERANGE; 139290375Srodrigc return (-1); 140290375Srodrigc } 141290375Srodrigc if (imsg->hdr.len > av) 142290375Srodrigc return (0); 143290375Srodrigc datalen = imsg->hdr.len - IMSG_HEADER_SIZE; 144290375Srodrigc ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; 145290375Srodrigc if (datalen == 0) 146290375Srodrigc imsg->data = NULL; 147290375Srodrigc else if ((imsg->data = malloc(datalen)) == NULL) 148290375Srodrigc return (-1); 149290375Srodrigc 150290375Srodrigc if (imsg->hdr.flags & IMSGF_HASFD) 151290375Srodrigc imsg->fd = imsg_get_fd(ibuf); 152290375Srodrigc else 153290375Srodrigc imsg->fd = -1; 154290375Srodrigc 155290375Srodrigc memcpy(imsg->data, ibuf->r.rptr, datalen); 156290375Srodrigc 157290375Srodrigc if (imsg->hdr.len < av) { 158290375Srodrigc left = av - imsg->hdr.len; 159290375Srodrigc memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left); 160290375Srodrigc ibuf->r.wpos = left; 161290375Srodrigc } else 162290375Srodrigc ibuf->r.wpos = 0; 163290375Srodrigc 164290375Srodrigc return (datalen + IMSG_HEADER_SIZE); 165290375Srodrigc} 166290375Srodrigc 167290375Srodrigcint 168290375Srodrigcimsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, 169290375Srodrigc pid_t pid, int fd, const void *data, u_int16_t datalen) 170290375Srodrigc{ 171290375Srodrigc struct ibuf *wbuf; 172290375Srodrigc 173290375Srodrigc if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) 174290375Srodrigc return (-1); 175290375Srodrigc 176290375Srodrigc if (imsg_add(wbuf, data, datalen) == -1) 177290375Srodrigc return (-1); 178290375Srodrigc 179290375Srodrigc wbuf->fd = fd; 180290375Srodrigc 181290375Srodrigc imsg_close(ibuf, wbuf); 182290375Srodrigc 183290375Srodrigc return (1); 184290375Srodrigc} 185290375Srodrigc 186290375Srodrigcint 187290375Srodrigcimsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, 188290375Srodrigc pid_t pid, int fd, const struct iovec *iov, int iovcnt) 189290375Srodrigc{ 190290375Srodrigc struct ibuf *wbuf; 191290375Srodrigc int i, datalen = 0; 192290375Srodrigc 193290375Srodrigc for (i = 0; i < iovcnt; i++) 194290375Srodrigc datalen += iov[i].iov_len; 195290375Srodrigc 196290375Srodrigc if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) 197290375Srodrigc return (-1); 198290375Srodrigc 199290375Srodrigc for (i = 0; i < iovcnt; i++) 200290375Srodrigc if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1) 201290375Srodrigc return (-1); 202290375Srodrigc 203290375Srodrigc wbuf->fd = fd; 204290375Srodrigc 205290375Srodrigc imsg_close(ibuf, wbuf); 206290375Srodrigc 207290375Srodrigc return (1); 208290375Srodrigc} 209290375Srodrigc 210290375Srodrigc/* ARGSUSED */ 211290375Srodrigcstruct ibuf * 212290375Srodrigcimsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, 213290375Srodrigc pid_t pid, u_int16_t datalen) 214290375Srodrigc{ 215290375Srodrigc struct ibuf *wbuf; 216290375Srodrigc struct imsg_hdr hdr; 217290375Srodrigc 218290375Srodrigc datalen += IMSG_HEADER_SIZE; 219290375Srodrigc if (datalen > MAX_IMSGSIZE) { 220290375Srodrigc errno = ERANGE; 221290375Srodrigc return (NULL); 222290375Srodrigc } 223290375Srodrigc 224290375Srodrigc hdr.type = type; 225290375Srodrigc hdr.flags = 0; 226290375Srodrigc hdr.peerid = peerid; 227290375Srodrigc if ((hdr.pid = pid) == 0) 228290375Srodrigc hdr.pid = ibuf->pid; 229290375Srodrigc if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { 230290375Srodrigc return (NULL); 231290375Srodrigc } 232290375Srodrigc if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) 233290375Srodrigc return (NULL); 234290375Srodrigc 235290375Srodrigc return (wbuf); 236290375Srodrigc} 237290375Srodrigc 238290375Srodrigcint 239290375Srodrigcimsg_add(struct ibuf *msg, const void *data, u_int16_t datalen) 240290375Srodrigc{ 241290375Srodrigc if (datalen) 242290375Srodrigc if (ibuf_add(msg, data, datalen) == -1) { 243290375Srodrigc ibuf_free(msg); 244290375Srodrigc return (-1); 245290375Srodrigc } 246290375Srodrigc return (datalen); 247290375Srodrigc} 248290375Srodrigc 249290375Srodrigcvoid 250290375Srodrigcimsg_close(struct imsgbuf *ibuf, struct ibuf *msg) 251290375Srodrigc{ 252290375Srodrigc struct imsg_hdr *hdr; 253290375Srodrigc 254290375Srodrigc hdr = (struct imsg_hdr *)msg->buf; 255290375Srodrigc 256290375Srodrigc hdr->flags &= ~IMSGF_HASFD; 257290375Srodrigc if (msg->fd != -1) 258290375Srodrigc hdr->flags |= IMSGF_HASFD; 259290375Srodrigc 260290375Srodrigc hdr->len = (u_int16_t)msg->wpos; 261290375Srodrigc 262290375Srodrigc ibuf_close(&ibuf->w, msg); 263290375Srodrigc} 264290375Srodrigc 265290375Srodrigcvoid 266290375Srodrigcimsg_free(struct imsg *imsg) 267290375Srodrigc{ 268290375Srodrigc free(imsg->data); 269290375Srodrigc} 270290375Srodrigc 271290375Srodrigcint 272290375Srodrigcimsg_get_fd(struct imsgbuf *ibuf) 273290375Srodrigc{ 274290375Srodrigc int fd; 275290375Srodrigc struct imsg_fd *ifd; 276290375Srodrigc 277290375Srodrigc if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL) 278290375Srodrigc return (-1); 279290375Srodrigc 280290375Srodrigc fd = ifd->fd; 281290375Srodrigc TAILQ_REMOVE(&ibuf->fds, ifd, entry); 282290375Srodrigc free(ifd); 283290375Srodrigc 284290375Srodrigc return (fd); 285290375Srodrigc} 286290375Srodrigc 287290375Srodrigcint 288290375Srodrigcimsg_flush(struct imsgbuf *ibuf) 289290375Srodrigc{ 290290375Srodrigc while (ibuf->w.queued) 291290375Srodrigc if (msgbuf_write(&ibuf->w) <= 0) 292290375Srodrigc return (-1); 293290375Srodrigc return (0); 294290375Srodrigc} 295290375Srodrigc 296290375Srodrigcvoid 297290375Srodrigcimsg_clear(struct imsgbuf *ibuf) 298290375Srodrigc{ 299290375Srodrigc int fd; 300290375Srodrigc 301290375Srodrigc msgbuf_clear(&ibuf->w); 302290375Srodrigc while ((fd = imsg_get_fd(ibuf)) != -1) 303290375Srodrigc close(fd); 304290375Srodrigc} 305