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 <sys/cdefs.h> 20 __FBSDID("$FreeBSD$"); 21 22 #include "dhcpd.h" 23 #include "privsep.h" 24 25 struct buf * 26 buf_open(size_t len) 27 { 28 struct buf *buf; 29 30 if ((buf = calloc(1, sizeof(struct buf))) == NULL) 31 return (NULL); 32 if ((buf->buf = malloc(len)) == NULL) { 33 free(buf); 34 return (NULL); 35 } 36 buf->size = len; 37 38 return (buf); 39 } 40 41 int 42 buf_add(struct buf *buf, const void *data, size_t len) 43 { 44 if (buf->wpos + len > buf->size) 45 return (-1); 46 47 memcpy(buf->buf + buf->wpos, data, len); 48 buf->wpos += len; 49 return (0); 50 } 51 52 int 53 buf_close(int sock, struct buf *buf) 54 { 55 ssize_t n; 56 57 do { 58 n = write(sock, buf->buf + buf->rpos, buf->size - buf->rpos); 59 if (n != -1) 60 buf->rpos += n; 61 if (n == 0) { /* connection closed */ 62 errno = 0; 63 return (-1); 64 } 65 } while (n == -1 && (errno == EAGAIN || errno == EINTR)); 66 67 if (buf->rpos < buf->size) 68 error("short write: wanted %lu got %ld bytes", 69 (unsigned long)buf->size, (long)buf->rpos); 70 71 free(buf->buf); 72 free(buf); 73 return (n); 74 } 75 76 ssize_t 77 buf_read(int sock, void *buf, size_t nbytes) 78 { 79 ssize_t n; 80 size_t r = 0; 81 char *p = buf; 82 83 do { 84 n = read(sock, p, nbytes); 85 if (n == 0) 86 error("connection closed"); 87 if (n != -1) { 88 r += (size_t)n; 89 p += n; 90 nbytes -= n; 91 } 92 } while (n == -1 && (errno == EINTR || errno == EAGAIN)); 93 94 if (n == -1) 95 error("buf_read: %m"); 96 97 if (r < nbytes) 98 error("short read: wanted %lu got %ld bytes", 99 (unsigned long)nbytes, (long)r); 100 101 return (r); 102 } 103 104 void 105 dispatch_imsg(struct interface_info *ifix, int fd) 106 { 107 struct imsg_hdr hdr; 108 char *medium, *reason, *filename, 109 *servername, *prefix; 110 size_t medium_len, reason_len, filename_len, 111 servername_len, optlen, prefix_len, totlen; 112 struct client_lease lease; 113 int ret, i; 114 struct buf *buf; 115 u_int16_t mtu; 116 117 buf_read(fd, &hdr, sizeof(hdr)); 118 119 switch (hdr.code) { 120 case IMSG_SCRIPT_INIT: 121 if (hdr.len < sizeof(hdr) + sizeof(size_t)) 122 error("corrupted message received"); 123 buf_read(fd, &medium_len, sizeof(medium_len)); 124 if (hdr.len < medium_len + sizeof(size_t) + sizeof(hdr) 125 + sizeof(size_t) || medium_len == SIZE_T_MAX) 126 error("corrupted message received"); 127 if (medium_len > 0) { 128 if ((medium = calloc(1, medium_len + 1)) == NULL) 129 error("%m"); 130 buf_read(fd, medium, medium_len); 131 } else 132 medium = NULL; 133 134 buf_read(fd, &reason_len, sizeof(reason_len)); 135 if (hdr.len < medium_len + reason_len + sizeof(hdr) || 136 reason_len == SIZE_T_MAX) 137 error("corrupted message received"); 138 if (reason_len > 0) { 139 if ((reason = calloc(1, reason_len + 1)) == NULL) 140 error("%m"); 141 buf_read(fd, reason, reason_len); 142 } else 143 reason = NULL; 144 145 priv_script_init(reason, medium); 146 free(reason); 147 free(medium); 148 break; 149 case IMSG_SCRIPT_WRITE_PARAMS: 150 bzero(&lease, sizeof lease); 151 totlen = sizeof(hdr) + sizeof(lease) + sizeof(size_t); 152 if (hdr.len < totlen) 153 error("corrupted message received"); 154 buf_read(fd, &lease, sizeof(lease)); 155 156 buf_read(fd, &filename_len, sizeof(filename_len)); 157 totlen += filename_len + sizeof(size_t); 158 if (hdr.len < totlen || filename_len == SIZE_T_MAX) 159 error("corrupted message received"); 160 if (filename_len > 0) { 161 if ((filename = calloc(1, filename_len + 1)) == NULL) 162 error("%m"); 163 buf_read(fd, filename, filename_len); 164 } else 165 filename = NULL; 166 167 buf_read(fd, &servername_len, sizeof(servername_len)); 168 totlen += servername_len + sizeof(size_t); 169 if (hdr.len < totlen || servername_len == SIZE_T_MAX) 170 error("corrupted message received"); 171 if (servername_len > 0) { 172 if ((servername = 173 calloc(1, servername_len + 1)) == NULL) 174 error("%m"); 175 buf_read(fd, servername, servername_len); 176 } else 177 servername = NULL; 178 179 buf_read(fd, &prefix_len, sizeof(prefix_len)); 180 totlen += prefix_len; 181 if (hdr.len < totlen || prefix_len == SIZE_T_MAX) 182 error("corrupted message received"); 183 if (prefix_len > 0) { 184 if ((prefix = calloc(1, prefix_len + 1)) == NULL) 185 error("%m"); 186 buf_read(fd, prefix, prefix_len); 187 } else 188 prefix = NULL; 189 190 for (i = 0; i < 256; i++) { 191 totlen += sizeof(optlen); 192 if (hdr.len < totlen) 193 error("corrupted message received"); 194 buf_read(fd, &optlen, sizeof(optlen)); 195 lease.options[i].data = NULL; 196 lease.options[i].len = optlen; 197 if (optlen > 0) { 198 totlen += optlen; 199 if (hdr.len < totlen || optlen == SIZE_T_MAX) 200 error("corrupted message received"); 201 lease.options[i].data = 202 calloc(1, optlen + 1); 203 if (lease.options[i].data == NULL) 204 error("%m"); 205 buf_read(fd, lease.options[i].data, optlen); 206 } 207 } 208 lease.server_name = servername; 209 lease.filename = filename; 210 211 priv_script_write_params(prefix, &lease); 212 213 free(servername); 214 free(filename); 215 free(prefix); 216 for (i = 0; i < 256; i++) 217 if (lease.options[i].len > 0) 218 free(lease.options[i].data); 219 break; 220 case IMSG_SCRIPT_GO: 221 if (hdr.len != sizeof(hdr)) 222 error("corrupted message received"); 223 224 ret = priv_script_go(); 225 226 hdr.code = IMSG_SCRIPT_GO_RET; 227 hdr.len = sizeof(struct imsg_hdr) + sizeof(int); 228 if ((buf = buf_open(hdr.len)) == NULL) 229 error("buf_open: %m"); 230 if (buf_add(buf, &hdr, sizeof(hdr))) 231 error("buf_add: %m"); 232 if (buf_add(buf, &ret, sizeof(ret))) 233 error("buf_add: %m"); 234 if (buf_close(fd, buf) == -1) 235 error("buf_close: %m"); 236 break; 237 case IMSG_SEND_PACKET: 238 send_packet_priv(ifix, &hdr, fd); 239 break; 240 case IMSG_SET_INTERFACE_MTU: 241 if (hdr.len < sizeof(hdr) + sizeof(u_int16_t)) 242 error("corrupted message received"); 243 244 buf_read(fd, &mtu, sizeof(u_int16_t)); 245 interface_set_mtu_priv(ifix->name, mtu); 246 break; 247 default: 248 error("received unknown message, code %d", hdr.code); 249 } 250 } 251