privsep.c revision 147072
1/* $OpenBSD: privsep.c,v 1.7 2004/05/10 18:34:42 deraadt Exp $ */ 2 3/* 4 * Copyright (c) 2004 Henning Brauer <henning@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 15 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 16 * OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include "dhcpd.h" 20#include "privsep.h" 21 22struct buf * 23buf_open(size_t len) 24{ 25 struct buf *buf; 26 27 if ((buf = calloc(1, sizeof(struct buf))) == NULL) 28 return (NULL); 29 if ((buf->buf = malloc(len)) == NULL) { 30 free(buf); 31 return (NULL); 32 } 33 buf->size = len; 34 35 return (buf); 36} 37 38int 39buf_add(struct buf *buf, void *data, size_t len) 40{ 41 if (buf->wpos + len > buf->size) 42 return (-1); 43 44 memcpy(buf->buf + buf->wpos, data, len); 45 buf->wpos += len; 46 return (0); 47} 48 49int 50buf_close(int sock, struct buf *buf) 51{ 52 ssize_t n; 53 54 do { 55 n = write(sock, buf->buf + buf->rpos, buf->size - buf->rpos); 56 if (n != -1) 57 buf->rpos += n; 58 if (n == 0) { /* connection closed */ 59 errno = 0; 60 return (-1); 61 } 62 } while (n == -1 && (errno == EAGAIN || errno == EINTR)); 63 64 if (buf->rpos < buf->size) 65 error("short write: wanted %lu got %ld bytes", 66 (unsigned long)buf->size, (long)buf->rpos); 67 68 free(buf->buf); 69 free(buf); 70 return (n); 71} 72 73ssize_t 74buf_read(int sock, void *buf, size_t nbytes) 75{ 76 ssize_t n, r = 0; 77 char *p = buf; 78 79 do { 80 n = read(sock, p, nbytes); 81 if (n == 0) 82 error("connection closed"); 83 if (n != -1) { 84 r += n; 85 p += n; 86 nbytes -= n; 87 } 88 } while (n == -1 && (errno == EINTR || errno == EAGAIN)); 89 90 if (n == -1) 91 error("buf_read: %m"); 92 93 if (r < nbytes) 94 error("short read: wanted %lu got %ld bytes", 95 (unsigned long)nbytes, (long)r); 96 97 return (r); 98} 99 100void 101dispatch_imsg(int fd) 102{ 103 struct imsg_hdr hdr; 104 char *medium, *reason, *filename, 105 *servername, *prefix; 106 size_t medium_len, reason_len, filename_len, 107 servername_len, prefix_len, totlen; 108 struct client_lease lease; 109 int ret, i, optlen; 110 struct buf *buf; 111 112 buf_read(fd, &hdr, sizeof(hdr)); 113 114 switch (hdr.code) { 115 case IMSG_SCRIPT_INIT: 116 if (hdr.len < sizeof(hdr) + sizeof(size_t)) 117 error("corrupted message received"); 118 buf_read(fd, &medium_len, sizeof(medium_len)); 119 if (hdr.len < medium_len + sizeof(size_t) + sizeof(hdr) 120 + sizeof(size_t) || medium_len == SIZE_T_MAX) 121 error("corrupted message received"); 122 if (medium_len > 0) { 123 if ((medium = calloc(1, medium_len + 1)) == NULL) 124 error("%m"); 125 buf_read(fd, medium, medium_len); 126 } else 127 medium = NULL; 128 129 buf_read(fd, &reason_len, sizeof(reason_len)); 130 if (hdr.len < medium_len + reason_len + sizeof(hdr) || 131 reason_len == SIZE_T_MAX) 132 error("corrupted message received"); 133 if (reason_len > 0) { 134 if ((reason = calloc(1, reason_len + 1)) == NULL) 135 error("%m"); 136 buf_read(fd, reason, reason_len); 137 } else 138 reason = NULL; 139 140 priv_script_init(reason, medium); 141 free(reason); 142 free(medium); 143 break; 144 case IMSG_SCRIPT_WRITE_PARAMS: 145 bzero(&lease, sizeof lease); 146 totlen = sizeof(hdr) + sizeof(lease) + sizeof(size_t); 147 if (hdr.len < totlen) 148 error("corrupted message received"); 149 buf_read(fd, &lease, sizeof(lease)); 150 151 buf_read(fd, &filename_len, sizeof(filename_len)); 152 totlen += filename_len + sizeof(size_t); 153 if (hdr.len < totlen || filename_len == SIZE_T_MAX) 154 error("corrupted message received"); 155 if (filename_len > 0) { 156 if ((filename = calloc(1, filename_len + 1)) == NULL) 157 error("%m"); 158 buf_read(fd, filename, filename_len); 159 } else 160 filename = NULL; 161 162 buf_read(fd, &servername_len, sizeof(servername_len)); 163 totlen += servername_len + sizeof(size_t); 164 if (hdr.len < totlen || servername_len == SIZE_T_MAX) 165 error("corrupted message received"); 166 if (servername_len > 0) { 167 if ((servername = 168 calloc(1, servername_len + 1)) == NULL) 169 error("%m"); 170 buf_read(fd, servername, servername_len); 171 } else 172 servername = NULL; 173 174 buf_read(fd, &prefix_len, sizeof(prefix_len)); 175 totlen += prefix_len; 176 if (hdr.len < totlen || prefix_len == SIZE_T_MAX) 177 error("corrupted message received"); 178 if (prefix_len > 0) { 179 if ((prefix = calloc(1, prefix_len + 1)) == NULL) 180 error("%m"); 181 buf_read(fd, prefix, prefix_len); 182 } else 183 prefix = NULL; 184 185 for (i = 0; i < 256; i++) { 186 totlen += sizeof(optlen); 187 if (hdr.len < totlen) 188 error("corrupted message received"); 189 buf_read(fd, &optlen, sizeof(optlen)); 190 lease.options[i].data = NULL; 191 lease.options[i].len = optlen; 192 if (optlen > 0) { 193 totlen += optlen; 194 if (hdr.len < totlen || optlen == SIZE_T_MAX) 195 error("corrupted message received"); 196 lease.options[i].data = 197 calloc(1, optlen + 1); 198 if (lease.options[i].data == NULL) 199 error("%m"); 200 buf_read(fd, lease.options[i].data, optlen); 201 } 202 } 203 lease.server_name = servername; 204 lease.filename = filename; 205 206 priv_script_write_params(prefix, &lease); 207 208 free(servername); 209 free(filename); 210 free(prefix); 211 for (i = 0; i < 256; i++) 212 if (lease.options[i].len > 0) 213 free(lease.options[i].data); 214 break; 215 case IMSG_SCRIPT_GO: 216 if (hdr.len != sizeof(hdr)) 217 error("corrupted message received"); 218 219 ret = priv_script_go(); 220 221 hdr.code = IMSG_SCRIPT_GO_RET; 222 hdr.len = sizeof(struct imsg_hdr) + sizeof(int); 223 if ((buf = buf_open(hdr.len)) == NULL) 224 error("buf_open: %m"); 225 if (buf_add(buf, &hdr, sizeof(hdr))) 226 error("buf_add: %m"); 227 if (buf_add(buf, &ret, sizeof(ret))) 228 error("buf_add: %m"); 229 if (buf_close(fd, buf) == -1) 230 error("buf_close: %m"); 231 break; 232 default: 233 error("received unknown message, code %d", hdr.code); 234 } 235} 236