147c08596SBrooks Davis /* $OpenBSD: privsep.c,v 1.7 2004/05/10 18:34:42 deraadt Exp $ */ 247c08596SBrooks Davis 347c08596SBrooks Davis /* 447c08596SBrooks Davis * Copyright (c) 2004 Henning Brauer <henning@openbsd.org> 547c08596SBrooks Davis * 647c08596SBrooks Davis * Permission to use, copy, modify, and distribute this software for any 747c08596SBrooks Davis * purpose with or without fee is hereby granted, provided that the above 847c08596SBrooks Davis * copyright notice and this permission notice appear in all copies. 947c08596SBrooks Davis * 1047c08596SBrooks Davis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1147c08596SBrooks Davis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1247c08596SBrooks Davis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1347c08596SBrooks Davis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1447c08596SBrooks Davis * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 1547c08596SBrooks Davis * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 1647c08596SBrooks Davis * OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE. 1747c08596SBrooks Davis */ 1847c08596SBrooks Davis 198794fdbbSBrooks Davis #include <sys/cdefs.h> 208794fdbbSBrooks Davis __FBSDID("$FreeBSD$"); 218794fdbbSBrooks Davis 2247c08596SBrooks Davis #include "dhcpd.h" 2347c08596SBrooks Davis #include "privsep.h" 2447c08596SBrooks Davis 2547c08596SBrooks Davis struct buf * 2647c08596SBrooks Davis buf_open(size_t len) 2747c08596SBrooks Davis { 2847c08596SBrooks Davis struct buf *buf; 2947c08596SBrooks Davis 3047c08596SBrooks Davis if ((buf = calloc(1, sizeof(struct buf))) == NULL) 3147c08596SBrooks Davis return (NULL); 3247c08596SBrooks Davis if ((buf->buf = malloc(len)) == NULL) { 3347c08596SBrooks Davis free(buf); 3447c08596SBrooks Davis return (NULL); 3547c08596SBrooks Davis } 3647c08596SBrooks Davis buf->size = len; 3747c08596SBrooks Davis 3847c08596SBrooks Davis return (buf); 3947c08596SBrooks Davis } 4047c08596SBrooks Davis 4147c08596SBrooks Davis int 4279a1d195SAlan Somers buf_add(struct buf *buf, const void *data, size_t len) 4347c08596SBrooks Davis { 4447c08596SBrooks Davis if (buf->wpos + len > buf->size) 4547c08596SBrooks Davis return (-1); 4647c08596SBrooks Davis 4747c08596SBrooks Davis memcpy(buf->buf + buf->wpos, data, len); 4847c08596SBrooks Davis buf->wpos += len; 4947c08596SBrooks Davis return (0); 5047c08596SBrooks Davis } 5147c08596SBrooks Davis 5247c08596SBrooks Davis int 5347c08596SBrooks Davis buf_close(int sock, struct buf *buf) 5447c08596SBrooks Davis { 5547c08596SBrooks Davis ssize_t n; 5647c08596SBrooks Davis 5747c08596SBrooks Davis do { 5847c08596SBrooks Davis n = write(sock, buf->buf + buf->rpos, buf->size - buf->rpos); 5947c08596SBrooks Davis if (n != -1) 6047c08596SBrooks Davis buf->rpos += n; 6147c08596SBrooks Davis if (n == 0) { /* connection closed */ 6247c08596SBrooks Davis errno = 0; 6347c08596SBrooks Davis return (-1); 6447c08596SBrooks Davis } 6547c08596SBrooks Davis } while (n == -1 && (errno == EAGAIN || errno == EINTR)); 6647c08596SBrooks Davis 6747c08596SBrooks Davis if (buf->rpos < buf->size) 6847c08596SBrooks Davis error("short write: wanted %lu got %ld bytes", 6947c08596SBrooks Davis (unsigned long)buf->size, (long)buf->rpos); 7047c08596SBrooks Davis 7147c08596SBrooks Davis free(buf->buf); 7247c08596SBrooks Davis free(buf); 7347c08596SBrooks Davis return (n); 7447c08596SBrooks Davis } 7547c08596SBrooks Davis 7647c08596SBrooks Davis ssize_t 7747c08596SBrooks Davis buf_read(int sock, void *buf, size_t nbytes) 7847c08596SBrooks Davis { 79afe6f835SAlan Somers ssize_t n; 80afe6f835SAlan Somers size_t r = 0; 8147c08596SBrooks Davis char *p = buf; 8247c08596SBrooks Davis 8347c08596SBrooks Davis do { 8447c08596SBrooks Davis n = read(sock, p, nbytes); 8547c08596SBrooks Davis if (n == 0) 8647c08596SBrooks Davis error("connection closed"); 8747c08596SBrooks Davis if (n != -1) { 88afe6f835SAlan Somers r += (size_t)n; 8947c08596SBrooks Davis p += n; 9047c08596SBrooks Davis nbytes -= n; 9147c08596SBrooks Davis } 9247c08596SBrooks Davis } while (n == -1 && (errno == EINTR || errno == EAGAIN)); 9347c08596SBrooks Davis 9447c08596SBrooks Davis if (n == -1) 9547c08596SBrooks Davis error("buf_read: %m"); 9647c08596SBrooks Davis 9747c08596SBrooks Davis if (r < nbytes) 9847c08596SBrooks Davis error("short read: wanted %lu got %ld bytes", 9947c08596SBrooks Davis (unsigned long)nbytes, (long)r); 10047c08596SBrooks Davis 10147c08596SBrooks Davis return (r); 10247c08596SBrooks Davis } 10347c08596SBrooks Davis 10447c08596SBrooks Davis void 105*71c6c44dSEitan Adler dispatch_imsg(struct interface_info *ifix, int fd) 10647c08596SBrooks Davis { 10747c08596SBrooks Davis struct imsg_hdr hdr; 10847c08596SBrooks Davis char *medium, *reason, *filename, 10947c08596SBrooks Davis *servername, *prefix; 11047c08596SBrooks Davis size_t medium_len, reason_len, filename_len, 111afe6f835SAlan Somers servername_len, optlen, prefix_len, totlen; 11247c08596SBrooks Davis struct client_lease lease; 113afe6f835SAlan Somers int ret, i; 11447c08596SBrooks Davis struct buf *buf; 115387016a5SConrad Meyer u_int16_t mtu; 11647c08596SBrooks Davis 11747c08596SBrooks Davis buf_read(fd, &hdr, sizeof(hdr)); 11847c08596SBrooks Davis 11947c08596SBrooks Davis switch (hdr.code) { 12047c08596SBrooks Davis case IMSG_SCRIPT_INIT: 12147c08596SBrooks Davis if (hdr.len < sizeof(hdr) + sizeof(size_t)) 12247c08596SBrooks Davis error("corrupted message received"); 12347c08596SBrooks Davis buf_read(fd, &medium_len, sizeof(medium_len)); 12447c08596SBrooks Davis if (hdr.len < medium_len + sizeof(size_t) + sizeof(hdr) 12547c08596SBrooks Davis + sizeof(size_t) || medium_len == SIZE_T_MAX) 12647c08596SBrooks Davis error("corrupted message received"); 12747c08596SBrooks Davis if (medium_len > 0) { 12847c08596SBrooks Davis if ((medium = calloc(1, medium_len + 1)) == NULL) 12947c08596SBrooks Davis error("%m"); 13047c08596SBrooks Davis buf_read(fd, medium, medium_len); 13147c08596SBrooks Davis } else 13247c08596SBrooks Davis medium = NULL; 13347c08596SBrooks Davis 13447c08596SBrooks Davis buf_read(fd, &reason_len, sizeof(reason_len)); 13547c08596SBrooks Davis if (hdr.len < medium_len + reason_len + sizeof(hdr) || 13647c08596SBrooks Davis reason_len == SIZE_T_MAX) 13747c08596SBrooks Davis error("corrupted message received"); 13847c08596SBrooks Davis if (reason_len > 0) { 13947c08596SBrooks Davis if ((reason = calloc(1, reason_len + 1)) == NULL) 14047c08596SBrooks Davis error("%m"); 14147c08596SBrooks Davis buf_read(fd, reason, reason_len); 14247c08596SBrooks Davis } else 14347c08596SBrooks Davis reason = NULL; 14447c08596SBrooks Davis 14547c08596SBrooks Davis priv_script_init(reason, medium); 14647c08596SBrooks Davis free(reason); 14747c08596SBrooks Davis free(medium); 14847c08596SBrooks Davis break; 14947c08596SBrooks Davis case IMSG_SCRIPT_WRITE_PARAMS: 15047c08596SBrooks Davis bzero(&lease, sizeof lease); 15147c08596SBrooks Davis totlen = sizeof(hdr) + sizeof(lease) + sizeof(size_t); 15247c08596SBrooks Davis if (hdr.len < totlen) 15347c08596SBrooks Davis error("corrupted message received"); 15447c08596SBrooks Davis buf_read(fd, &lease, sizeof(lease)); 15547c08596SBrooks Davis 15647c08596SBrooks Davis buf_read(fd, &filename_len, sizeof(filename_len)); 15747c08596SBrooks Davis totlen += filename_len + sizeof(size_t); 15847c08596SBrooks Davis if (hdr.len < totlen || filename_len == SIZE_T_MAX) 15947c08596SBrooks Davis error("corrupted message received"); 16047c08596SBrooks Davis if (filename_len > 0) { 16147c08596SBrooks Davis if ((filename = calloc(1, filename_len + 1)) == NULL) 16247c08596SBrooks Davis error("%m"); 16347c08596SBrooks Davis buf_read(fd, filename, filename_len); 16447c08596SBrooks Davis } else 16547c08596SBrooks Davis filename = NULL; 16647c08596SBrooks Davis 16747c08596SBrooks Davis buf_read(fd, &servername_len, sizeof(servername_len)); 16847c08596SBrooks Davis totlen += servername_len + sizeof(size_t); 16947c08596SBrooks Davis if (hdr.len < totlen || servername_len == SIZE_T_MAX) 17047c08596SBrooks Davis error("corrupted message received"); 17147c08596SBrooks Davis if (servername_len > 0) { 17247c08596SBrooks Davis if ((servername = 17347c08596SBrooks Davis calloc(1, servername_len + 1)) == NULL) 17447c08596SBrooks Davis error("%m"); 17547c08596SBrooks Davis buf_read(fd, servername, servername_len); 17647c08596SBrooks Davis } else 17747c08596SBrooks Davis servername = NULL; 17847c08596SBrooks Davis 17947c08596SBrooks Davis buf_read(fd, &prefix_len, sizeof(prefix_len)); 18047c08596SBrooks Davis totlen += prefix_len; 18147c08596SBrooks Davis if (hdr.len < totlen || prefix_len == SIZE_T_MAX) 18247c08596SBrooks Davis error("corrupted message received"); 18347c08596SBrooks Davis if (prefix_len > 0) { 18447c08596SBrooks Davis if ((prefix = calloc(1, prefix_len + 1)) == NULL) 18547c08596SBrooks Davis error("%m"); 18647c08596SBrooks Davis buf_read(fd, prefix, prefix_len); 18747c08596SBrooks Davis } else 18847c08596SBrooks Davis prefix = NULL; 18947c08596SBrooks Davis 19047c08596SBrooks Davis for (i = 0; i < 256; i++) { 19147c08596SBrooks Davis totlen += sizeof(optlen); 19247c08596SBrooks Davis if (hdr.len < totlen) 19347c08596SBrooks Davis error("corrupted message received"); 19447c08596SBrooks Davis buf_read(fd, &optlen, sizeof(optlen)); 19547c08596SBrooks Davis lease.options[i].data = NULL; 19647c08596SBrooks Davis lease.options[i].len = optlen; 19747c08596SBrooks Davis if (optlen > 0) { 19847c08596SBrooks Davis totlen += optlen; 19947c08596SBrooks Davis if (hdr.len < totlen || optlen == SIZE_T_MAX) 20047c08596SBrooks Davis error("corrupted message received"); 20147c08596SBrooks Davis lease.options[i].data = 20247c08596SBrooks Davis calloc(1, optlen + 1); 20347c08596SBrooks Davis if (lease.options[i].data == NULL) 20447c08596SBrooks Davis error("%m"); 20547c08596SBrooks Davis buf_read(fd, lease.options[i].data, optlen); 20647c08596SBrooks Davis } 20747c08596SBrooks Davis } 20847c08596SBrooks Davis lease.server_name = servername; 20947c08596SBrooks Davis lease.filename = filename; 21047c08596SBrooks Davis 21147c08596SBrooks Davis priv_script_write_params(prefix, &lease); 21247c08596SBrooks Davis 21347c08596SBrooks Davis free(servername); 21447c08596SBrooks Davis free(filename); 21547c08596SBrooks Davis free(prefix); 21647c08596SBrooks Davis for (i = 0; i < 256; i++) 21747c08596SBrooks Davis if (lease.options[i].len > 0) 21847c08596SBrooks Davis free(lease.options[i].data); 21947c08596SBrooks Davis break; 22047c08596SBrooks Davis case IMSG_SCRIPT_GO: 22147c08596SBrooks Davis if (hdr.len != sizeof(hdr)) 22247c08596SBrooks Davis error("corrupted message received"); 22347c08596SBrooks Davis 22447c08596SBrooks Davis ret = priv_script_go(); 22547c08596SBrooks Davis 22647c08596SBrooks Davis hdr.code = IMSG_SCRIPT_GO_RET; 22747c08596SBrooks Davis hdr.len = sizeof(struct imsg_hdr) + sizeof(int); 22847c08596SBrooks Davis if ((buf = buf_open(hdr.len)) == NULL) 22947c08596SBrooks Davis error("buf_open: %m"); 23047c08596SBrooks Davis if (buf_add(buf, &hdr, sizeof(hdr))) 23147c08596SBrooks Davis error("buf_add: %m"); 23247c08596SBrooks Davis if (buf_add(buf, &ret, sizeof(ret))) 23347c08596SBrooks Davis error("buf_add: %m"); 23447c08596SBrooks Davis if (buf_close(fd, buf) == -1) 23547c08596SBrooks Davis error("buf_close: %m"); 23647c08596SBrooks Davis break; 237235eb530SPawel Jakub Dawidek case IMSG_SEND_PACKET: 238*71c6c44dSEitan Adler send_packet_priv(ifix, &hdr, fd); 239235eb530SPawel Jakub Dawidek break; 240387016a5SConrad Meyer case IMSG_SET_INTERFACE_MTU: 241387016a5SConrad Meyer if (hdr.len < sizeof(hdr) + sizeof(u_int16_t)) 242387016a5SConrad Meyer error("corrupted message received"); 243387016a5SConrad Meyer 244387016a5SConrad Meyer buf_read(fd, &mtu, sizeof(u_int16_t)); 245*71c6c44dSEitan Adler interface_set_mtu_priv(ifix->name, mtu); 246387016a5SConrad Meyer break; 24747c08596SBrooks Davis default: 24847c08596SBrooks Davis error("received unknown message, code %d", hdr.code); 24947c08596SBrooks Davis } 25047c08596SBrooks Davis } 251