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