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