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 1947c08596SBrooks Davis #include "dhcpd.h" 2047c08596SBrooks Davis #include "privsep.h" 2147c08596SBrooks Davis 2247c08596SBrooks Davis struct buf * 2347c08596SBrooks Davis buf_open(size_t len) 2447c08596SBrooks Davis { 2547c08596SBrooks Davis struct buf *buf; 2647c08596SBrooks Davis 2747c08596SBrooks Davis if ((buf = calloc(1, sizeof(struct buf))) == NULL) 2847c08596SBrooks Davis return (NULL); 2947c08596SBrooks Davis if ((buf->buf = malloc(len)) == NULL) { 3047c08596SBrooks Davis free(buf); 3147c08596SBrooks Davis return (NULL); 3247c08596SBrooks Davis } 3347c08596SBrooks Davis buf->size = len; 3447c08596SBrooks Davis 3547c08596SBrooks Davis return (buf); 3647c08596SBrooks Davis } 3747c08596SBrooks Davis 3847c08596SBrooks Davis int 3947c08596SBrooks Davis buf_add(struct buf *buf, void *data, size_t len) 4047c08596SBrooks Davis { 4147c08596SBrooks Davis if (buf->wpos + len > buf->size) 4247c08596SBrooks Davis return (-1); 4347c08596SBrooks Davis 4447c08596SBrooks Davis memcpy(buf->buf + buf->wpos, data, len); 4547c08596SBrooks Davis buf->wpos += len; 4647c08596SBrooks Davis return (0); 4747c08596SBrooks Davis } 4847c08596SBrooks Davis 4947c08596SBrooks Davis int 5047c08596SBrooks Davis buf_close(int sock, struct buf *buf) 5147c08596SBrooks Davis { 5247c08596SBrooks Davis ssize_t n; 5347c08596SBrooks Davis 5447c08596SBrooks Davis do { 5547c08596SBrooks Davis n = write(sock, buf->buf + buf->rpos, buf->size - buf->rpos); 5647c08596SBrooks Davis if (n != -1) 5747c08596SBrooks Davis buf->rpos += n; 5847c08596SBrooks Davis if (n == 0) { /* connection closed */ 5947c08596SBrooks Davis errno = 0; 6047c08596SBrooks Davis return (-1); 6147c08596SBrooks Davis } 6247c08596SBrooks Davis } while (n == -1 && (errno == EAGAIN || errno == EINTR)); 6347c08596SBrooks Davis 6447c08596SBrooks Davis if (buf->rpos < buf->size) 6547c08596SBrooks Davis error("short write: wanted %lu got %ld bytes", 6647c08596SBrooks Davis (unsigned long)buf->size, (long)buf->rpos); 6747c08596SBrooks Davis 6847c08596SBrooks Davis free(buf->buf); 6947c08596SBrooks Davis free(buf); 7047c08596SBrooks Davis return (n); 7147c08596SBrooks Davis } 7247c08596SBrooks Davis 7347c08596SBrooks Davis ssize_t 7447c08596SBrooks Davis buf_read(int sock, void *buf, size_t nbytes) 7547c08596SBrooks Davis { 7647c08596SBrooks Davis ssize_t n, r = 0; 7747c08596SBrooks Davis char *p = buf; 7847c08596SBrooks Davis 7947c08596SBrooks Davis do { 8047c08596SBrooks Davis n = read(sock, p, nbytes); 8147c08596SBrooks Davis if (n == 0) 8247c08596SBrooks Davis error("connection closed"); 8347c08596SBrooks Davis if (n != -1) { 8447c08596SBrooks Davis r += n; 8547c08596SBrooks Davis p += n; 8647c08596SBrooks Davis nbytes -= n; 8747c08596SBrooks Davis } 8847c08596SBrooks Davis } while (n == -1 && (errno == EINTR || errno == EAGAIN)); 8947c08596SBrooks Davis 9047c08596SBrooks Davis if (n == -1) 9147c08596SBrooks Davis error("buf_read: %m"); 9247c08596SBrooks Davis 9347c08596SBrooks Davis if (r < nbytes) 9447c08596SBrooks Davis error("short read: wanted %lu got %ld bytes", 9547c08596SBrooks Davis (unsigned long)nbytes, (long)r); 9647c08596SBrooks Davis 9747c08596SBrooks Davis return (r); 9847c08596SBrooks Davis } 9947c08596SBrooks Davis 10047c08596SBrooks Davis void 10147c08596SBrooks Davis dispatch_imsg(int fd) 10247c08596SBrooks Davis { 10347c08596SBrooks Davis struct imsg_hdr hdr; 10447c08596SBrooks Davis char *medium, *reason, *filename, 10547c08596SBrooks Davis *servername, *prefix; 10647c08596SBrooks Davis size_t medium_len, reason_len, filename_len, 10747c08596SBrooks Davis servername_len, prefix_len, totlen; 10847c08596SBrooks Davis struct client_lease lease; 10947c08596SBrooks Davis int ret, i, optlen; 11047c08596SBrooks Davis struct buf *buf; 11147c08596SBrooks Davis 11247c08596SBrooks Davis buf_read(fd, &hdr, sizeof(hdr)); 11347c08596SBrooks Davis 11447c08596SBrooks Davis switch (hdr.code) { 11547c08596SBrooks Davis case IMSG_SCRIPT_INIT: 11647c08596SBrooks Davis if (hdr.len < sizeof(hdr) + sizeof(size_t)) 11747c08596SBrooks Davis error("corrupted message received"); 11847c08596SBrooks Davis buf_read(fd, &medium_len, sizeof(medium_len)); 11947c08596SBrooks Davis if (hdr.len < medium_len + sizeof(size_t) + sizeof(hdr) 12047c08596SBrooks Davis + sizeof(size_t) || medium_len == SIZE_T_MAX) 12147c08596SBrooks Davis error("corrupted message received"); 12247c08596SBrooks Davis if (medium_len > 0) { 12347c08596SBrooks Davis if ((medium = calloc(1, medium_len + 1)) == NULL) 12447c08596SBrooks Davis error("%m"); 12547c08596SBrooks Davis buf_read(fd, medium, medium_len); 12647c08596SBrooks Davis } else 12747c08596SBrooks Davis medium = NULL; 12847c08596SBrooks Davis 12947c08596SBrooks Davis buf_read(fd, &reason_len, sizeof(reason_len)); 13047c08596SBrooks Davis if (hdr.len < medium_len + reason_len + sizeof(hdr) || 13147c08596SBrooks Davis reason_len == SIZE_T_MAX) 13247c08596SBrooks Davis error("corrupted message received"); 13347c08596SBrooks Davis if (reason_len > 0) { 13447c08596SBrooks Davis if ((reason = calloc(1, reason_len + 1)) == NULL) 13547c08596SBrooks Davis error("%m"); 13647c08596SBrooks Davis buf_read(fd, reason, reason_len); 13747c08596SBrooks Davis } else 13847c08596SBrooks Davis reason = NULL; 13947c08596SBrooks Davis 14047c08596SBrooks Davis priv_script_init(reason, medium); 14147c08596SBrooks Davis free(reason); 14247c08596SBrooks Davis free(medium); 14347c08596SBrooks Davis break; 14447c08596SBrooks Davis case IMSG_SCRIPT_WRITE_PARAMS: 14547c08596SBrooks Davis bzero(&lease, sizeof lease); 14647c08596SBrooks Davis totlen = sizeof(hdr) + sizeof(lease) + sizeof(size_t); 14747c08596SBrooks Davis if (hdr.len < totlen) 14847c08596SBrooks Davis error("corrupted message received"); 14947c08596SBrooks Davis buf_read(fd, &lease, sizeof(lease)); 15047c08596SBrooks Davis 15147c08596SBrooks Davis buf_read(fd, &filename_len, sizeof(filename_len)); 15247c08596SBrooks Davis totlen += filename_len + sizeof(size_t); 15347c08596SBrooks Davis if (hdr.len < totlen || filename_len == SIZE_T_MAX) 15447c08596SBrooks Davis error("corrupted message received"); 15547c08596SBrooks Davis if (filename_len > 0) { 15647c08596SBrooks Davis if ((filename = calloc(1, filename_len + 1)) == NULL) 15747c08596SBrooks Davis error("%m"); 15847c08596SBrooks Davis buf_read(fd, filename, filename_len); 15947c08596SBrooks Davis } else 16047c08596SBrooks Davis filename = NULL; 16147c08596SBrooks Davis 16247c08596SBrooks Davis buf_read(fd, &servername_len, sizeof(servername_len)); 16347c08596SBrooks Davis totlen += servername_len + sizeof(size_t); 16447c08596SBrooks Davis if (hdr.len < totlen || servername_len == SIZE_T_MAX) 16547c08596SBrooks Davis error("corrupted message received"); 16647c08596SBrooks Davis if (servername_len > 0) { 16747c08596SBrooks Davis if ((servername = 16847c08596SBrooks Davis calloc(1, servername_len + 1)) == NULL) 16947c08596SBrooks Davis error("%m"); 17047c08596SBrooks Davis buf_read(fd, servername, servername_len); 17147c08596SBrooks Davis } else 17247c08596SBrooks Davis servername = NULL; 17347c08596SBrooks Davis 17447c08596SBrooks Davis buf_read(fd, &prefix_len, sizeof(prefix_len)); 17547c08596SBrooks Davis totlen += prefix_len; 17647c08596SBrooks Davis if (hdr.len < totlen || prefix_len == SIZE_T_MAX) 17747c08596SBrooks Davis error("corrupted message received"); 17847c08596SBrooks Davis if (prefix_len > 0) { 17947c08596SBrooks Davis if ((prefix = calloc(1, prefix_len + 1)) == NULL) 18047c08596SBrooks Davis error("%m"); 18147c08596SBrooks Davis buf_read(fd, prefix, prefix_len); 18247c08596SBrooks Davis } else 18347c08596SBrooks Davis prefix = NULL; 18447c08596SBrooks Davis 18547c08596SBrooks Davis for (i = 0; i < 256; i++) { 18647c08596SBrooks Davis totlen += sizeof(optlen); 18747c08596SBrooks Davis if (hdr.len < totlen) 18847c08596SBrooks Davis error("corrupted message received"); 18947c08596SBrooks Davis buf_read(fd, &optlen, sizeof(optlen)); 19047c08596SBrooks Davis lease.options[i].data = NULL; 19147c08596SBrooks Davis lease.options[i].len = optlen; 19247c08596SBrooks Davis if (optlen > 0) { 19347c08596SBrooks Davis totlen += optlen; 19447c08596SBrooks Davis if (hdr.len < totlen || optlen == SIZE_T_MAX) 19547c08596SBrooks Davis error("corrupted message received"); 19647c08596SBrooks Davis lease.options[i].data = 19747c08596SBrooks Davis calloc(1, optlen + 1); 19847c08596SBrooks Davis if (lease.options[i].data == NULL) 19947c08596SBrooks Davis error("%m"); 20047c08596SBrooks Davis buf_read(fd, lease.options[i].data, optlen); 20147c08596SBrooks Davis } 20247c08596SBrooks Davis } 20347c08596SBrooks Davis lease.server_name = servername; 20447c08596SBrooks Davis lease.filename = filename; 20547c08596SBrooks Davis 20647c08596SBrooks Davis priv_script_write_params(prefix, &lease); 20747c08596SBrooks Davis 20847c08596SBrooks Davis free(servername); 20947c08596SBrooks Davis free(filename); 21047c08596SBrooks Davis free(prefix); 21147c08596SBrooks Davis for (i = 0; i < 256; i++) 21247c08596SBrooks Davis if (lease.options[i].len > 0) 21347c08596SBrooks Davis free(lease.options[i].data); 21447c08596SBrooks Davis break; 21547c08596SBrooks Davis case IMSG_SCRIPT_GO: 21647c08596SBrooks Davis if (hdr.len != sizeof(hdr)) 21747c08596SBrooks Davis error("corrupted message received"); 21847c08596SBrooks Davis 21947c08596SBrooks Davis ret = priv_script_go(); 22047c08596SBrooks Davis 22147c08596SBrooks Davis hdr.code = IMSG_SCRIPT_GO_RET; 22247c08596SBrooks Davis hdr.len = sizeof(struct imsg_hdr) + sizeof(int); 22347c08596SBrooks Davis if ((buf = buf_open(hdr.len)) == NULL) 22447c08596SBrooks Davis error("buf_open: %m"); 22547c08596SBrooks Davis if (buf_add(buf, &hdr, sizeof(hdr))) 22647c08596SBrooks Davis error("buf_add: %m"); 22747c08596SBrooks Davis if (buf_add(buf, &ret, sizeof(ret))) 22847c08596SBrooks Davis error("buf_add: %m"); 22947c08596SBrooks Davis if (buf_close(fd, buf) == -1) 23047c08596SBrooks Davis error("buf_close: %m"); 23147c08596SBrooks Davis break; 23247c08596SBrooks Davis default: 23347c08596SBrooks Davis error("received unknown message, code %d", hdr.code); 23447c08596SBrooks Davis } 23547c08596SBrooks Davis } 236