1147072Sbrooks/* $OpenBSD: privsep.c,v 1.7 2004/05/10 18:34:42 deraadt Exp $ */ 2147072Sbrooks 3147072Sbrooks/* 4147072Sbrooks * Copyright (c) 2004 Henning Brauer <henning@openbsd.org> 5147072Sbrooks * 6147072Sbrooks * Permission to use, copy, modify, and distribute this software for any 7147072Sbrooks * purpose with or without fee is hereby granted, provided that the above 8147072Sbrooks * copyright notice and this permission notice appear in all copies. 9147072Sbrooks * 10147072Sbrooks * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11147072Sbrooks * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12147072Sbrooks * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13147072Sbrooks * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14147072Sbrooks * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 15147072Sbrooks * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 16147072Sbrooks * OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE. 17147072Sbrooks */ 18147072Sbrooks 19149399Sbrooks#include <sys/cdefs.h> 20149399Sbrooks__FBSDID("$FreeBSD$"); 21149399Sbrooks 22147072Sbrooks#include "dhcpd.h" 23147072Sbrooks#include "privsep.h" 24147072Sbrooks 25147072Sbrooksstruct buf * 26147072Sbrooksbuf_open(size_t len) 27147072Sbrooks{ 28147072Sbrooks struct buf *buf; 29147072Sbrooks 30147072Sbrooks if ((buf = calloc(1, sizeof(struct buf))) == NULL) 31147072Sbrooks return (NULL); 32147072Sbrooks if ((buf->buf = malloc(len)) == NULL) { 33147072Sbrooks free(buf); 34147072Sbrooks return (NULL); 35147072Sbrooks } 36147072Sbrooks buf->size = len; 37147072Sbrooks 38147072Sbrooks return (buf); 39147072Sbrooks} 40147072Sbrooks 41147072Sbrooksint 42147072Sbrooksbuf_add(struct buf *buf, void *data, size_t len) 43147072Sbrooks{ 44147072Sbrooks if (buf->wpos + len > buf->size) 45147072Sbrooks return (-1); 46147072Sbrooks 47147072Sbrooks memcpy(buf->buf + buf->wpos, data, len); 48147072Sbrooks buf->wpos += len; 49147072Sbrooks return (0); 50147072Sbrooks} 51147072Sbrooks 52147072Sbrooksint 53147072Sbrooksbuf_close(int sock, struct buf *buf) 54147072Sbrooks{ 55147072Sbrooks ssize_t n; 56147072Sbrooks 57147072Sbrooks do { 58147072Sbrooks n = write(sock, buf->buf + buf->rpos, buf->size - buf->rpos); 59147072Sbrooks if (n != -1) 60147072Sbrooks buf->rpos += n; 61147072Sbrooks if (n == 0) { /* connection closed */ 62147072Sbrooks errno = 0; 63147072Sbrooks return (-1); 64147072Sbrooks } 65147072Sbrooks } while (n == -1 && (errno == EAGAIN || errno == EINTR)); 66147072Sbrooks 67147072Sbrooks if (buf->rpos < buf->size) 68147072Sbrooks error("short write: wanted %lu got %ld bytes", 69147072Sbrooks (unsigned long)buf->size, (long)buf->rpos); 70147072Sbrooks 71147072Sbrooks free(buf->buf); 72147072Sbrooks free(buf); 73147072Sbrooks return (n); 74147072Sbrooks} 75147072Sbrooks 76147072Sbrooksssize_t 77147072Sbrooksbuf_read(int sock, void *buf, size_t nbytes) 78147072Sbrooks{ 79147072Sbrooks ssize_t n, r = 0; 80147072Sbrooks char *p = buf; 81147072Sbrooks 82147072Sbrooks do { 83147072Sbrooks n = read(sock, p, nbytes); 84147072Sbrooks if (n == 0) 85147072Sbrooks error("connection closed"); 86147072Sbrooks if (n != -1) { 87147072Sbrooks r += n; 88147072Sbrooks p += n; 89147072Sbrooks nbytes -= n; 90147072Sbrooks } 91147072Sbrooks } while (n == -1 && (errno == EINTR || errno == EAGAIN)); 92147072Sbrooks 93147072Sbrooks if (n == -1) 94147072Sbrooks error("buf_read: %m"); 95147072Sbrooks 96147072Sbrooks if (r < nbytes) 97147072Sbrooks error("short read: wanted %lu got %ld bytes", 98147072Sbrooks (unsigned long)nbytes, (long)r); 99147072Sbrooks 100147072Sbrooks return (r); 101147072Sbrooks} 102147072Sbrooks 103147072Sbrooksvoid 104147072Sbrooksdispatch_imsg(int fd) 105147072Sbrooks{ 106147072Sbrooks struct imsg_hdr hdr; 107147072Sbrooks char *medium, *reason, *filename, 108147072Sbrooks *servername, *prefix; 109147072Sbrooks size_t medium_len, reason_len, filename_len, 110147072Sbrooks servername_len, prefix_len, totlen; 111147072Sbrooks struct client_lease lease; 112147072Sbrooks int ret, i, optlen; 113147072Sbrooks struct buf *buf; 114147072Sbrooks 115147072Sbrooks buf_read(fd, &hdr, sizeof(hdr)); 116147072Sbrooks 117147072Sbrooks switch (hdr.code) { 118147072Sbrooks case IMSG_SCRIPT_INIT: 119147072Sbrooks if (hdr.len < sizeof(hdr) + sizeof(size_t)) 120147072Sbrooks error("corrupted message received"); 121147072Sbrooks buf_read(fd, &medium_len, sizeof(medium_len)); 122147072Sbrooks if (hdr.len < medium_len + sizeof(size_t) + sizeof(hdr) 123147072Sbrooks + sizeof(size_t) || medium_len == SIZE_T_MAX) 124147072Sbrooks error("corrupted message received"); 125147072Sbrooks if (medium_len > 0) { 126147072Sbrooks if ((medium = calloc(1, medium_len + 1)) == NULL) 127147072Sbrooks error("%m"); 128147072Sbrooks buf_read(fd, medium, medium_len); 129147072Sbrooks } else 130147072Sbrooks medium = NULL; 131147072Sbrooks 132147072Sbrooks buf_read(fd, &reason_len, sizeof(reason_len)); 133147072Sbrooks if (hdr.len < medium_len + reason_len + sizeof(hdr) || 134147072Sbrooks reason_len == SIZE_T_MAX) 135147072Sbrooks error("corrupted message received"); 136147072Sbrooks if (reason_len > 0) { 137147072Sbrooks if ((reason = calloc(1, reason_len + 1)) == NULL) 138147072Sbrooks error("%m"); 139147072Sbrooks buf_read(fd, reason, reason_len); 140147072Sbrooks } else 141147072Sbrooks reason = NULL; 142147072Sbrooks 143147072Sbrooks priv_script_init(reason, medium); 144147072Sbrooks free(reason); 145147072Sbrooks free(medium); 146147072Sbrooks break; 147147072Sbrooks case IMSG_SCRIPT_WRITE_PARAMS: 148147072Sbrooks bzero(&lease, sizeof lease); 149147072Sbrooks totlen = sizeof(hdr) + sizeof(lease) + sizeof(size_t); 150147072Sbrooks if (hdr.len < totlen) 151147072Sbrooks error("corrupted message received"); 152147072Sbrooks buf_read(fd, &lease, sizeof(lease)); 153147072Sbrooks 154147072Sbrooks buf_read(fd, &filename_len, sizeof(filename_len)); 155147072Sbrooks totlen += filename_len + sizeof(size_t); 156147072Sbrooks if (hdr.len < totlen || filename_len == SIZE_T_MAX) 157147072Sbrooks error("corrupted message received"); 158147072Sbrooks if (filename_len > 0) { 159147072Sbrooks if ((filename = calloc(1, filename_len + 1)) == NULL) 160147072Sbrooks error("%m"); 161147072Sbrooks buf_read(fd, filename, filename_len); 162147072Sbrooks } else 163147072Sbrooks filename = NULL; 164147072Sbrooks 165147072Sbrooks buf_read(fd, &servername_len, sizeof(servername_len)); 166147072Sbrooks totlen += servername_len + sizeof(size_t); 167147072Sbrooks if (hdr.len < totlen || servername_len == SIZE_T_MAX) 168147072Sbrooks error("corrupted message received"); 169147072Sbrooks if (servername_len > 0) { 170147072Sbrooks if ((servername = 171147072Sbrooks calloc(1, servername_len + 1)) == NULL) 172147072Sbrooks error("%m"); 173147072Sbrooks buf_read(fd, servername, servername_len); 174147072Sbrooks } else 175147072Sbrooks servername = NULL; 176147072Sbrooks 177147072Sbrooks buf_read(fd, &prefix_len, sizeof(prefix_len)); 178147072Sbrooks totlen += prefix_len; 179147072Sbrooks if (hdr.len < totlen || prefix_len == SIZE_T_MAX) 180147072Sbrooks error("corrupted message received"); 181147072Sbrooks if (prefix_len > 0) { 182147072Sbrooks if ((prefix = calloc(1, prefix_len + 1)) == NULL) 183147072Sbrooks error("%m"); 184147072Sbrooks buf_read(fd, prefix, prefix_len); 185147072Sbrooks } else 186147072Sbrooks prefix = NULL; 187147072Sbrooks 188147072Sbrooks for (i = 0; i < 256; i++) { 189147072Sbrooks totlen += sizeof(optlen); 190147072Sbrooks if (hdr.len < totlen) 191147072Sbrooks error("corrupted message received"); 192147072Sbrooks buf_read(fd, &optlen, sizeof(optlen)); 193147072Sbrooks lease.options[i].data = NULL; 194147072Sbrooks lease.options[i].len = optlen; 195147072Sbrooks if (optlen > 0) { 196147072Sbrooks totlen += optlen; 197147072Sbrooks if (hdr.len < totlen || optlen == SIZE_T_MAX) 198147072Sbrooks error("corrupted message received"); 199147072Sbrooks lease.options[i].data = 200147072Sbrooks calloc(1, optlen + 1); 201147072Sbrooks if (lease.options[i].data == NULL) 202147072Sbrooks error("%m"); 203147072Sbrooks buf_read(fd, lease.options[i].data, optlen); 204147072Sbrooks } 205147072Sbrooks } 206147072Sbrooks lease.server_name = servername; 207147072Sbrooks lease.filename = filename; 208147072Sbrooks 209147072Sbrooks priv_script_write_params(prefix, &lease); 210147072Sbrooks 211147072Sbrooks free(servername); 212147072Sbrooks free(filename); 213147072Sbrooks free(prefix); 214147072Sbrooks for (i = 0; i < 256; i++) 215147072Sbrooks if (lease.options[i].len > 0) 216147072Sbrooks free(lease.options[i].data); 217147072Sbrooks break; 218147072Sbrooks case IMSG_SCRIPT_GO: 219147072Sbrooks if (hdr.len != sizeof(hdr)) 220147072Sbrooks error("corrupted message received"); 221147072Sbrooks 222147072Sbrooks ret = priv_script_go(); 223147072Sbrooks 224147072Sbrooks hdr.code = IMSG_SCRIPT_GO_RET; 225147072Sbrooks hdr.len = sizeof(struct imsg_hdr) + sizeof(int); 226147072Sbrooks if ((buf = buf_open(hdr.len)) == NULL) 227147072Sbrooks error("buf_open: %m"); 228147072Sbrooks if (buf_add(buf, &hdr, sizeof(hdr))) 229147072Sbrooks error("buf_add: %m"); 230147072Sbrooks if (buf_add(buf, &ret, sizeof(ret))) 231147072Sbrooks error("buf_add: %m"); 232147072Sbrooks if (buf_close(fd, buf) == -1) 233147072Sbrooks error("buf_close: %m"); 234147072Sbrooks break; 235147072Sbrooks default: 236147072Sbrooks error("received unknown message, code %d", hdr.code); 237147072Sbrooks } 238147072Sbrooks} 239