1 /* $OpenBSD: src/sbin/dhclient/privsep.c,v 1.16 2011/04/04 11:14:52 krw 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 22 struct buf * 23 buf_open(size_t len) 24 { 25 struct buf *buf; 26 27 if ((buf = calloc(1, sizeof(struct buf))) == NULL) 28 error("buf_open: %m"); 29 if ((buf->buf = malloc(len)) == NULL) { 30 free(buf); 31 error("buf_open: %m"); 32 } 33 buf->size = len; 34 35 return (buf); 36 } 37 38 void 39 buf_add(struct buf *buf, void *data, size_t len) 40 { 41 if (len == 0) 42 return; 43 44 if (buf->wpos + len > buf->size) 45 error("buf_add: %m"); 46 47 memcpy(buf->buf + buf->wpos, data, len); 48 buf->wpos += len; 49 } 50 51 void 52 buf_close(int sock, struct buf *buf) 53 { 54 ssize_t n; 55 56 do { 57 n = write(sock, buf->buf + buf->rpos, buf->size - buf->rpos); 58 if (n == 0) /* connection closed */ 59 error("buf_close (connection closed)"); 60 if (n != -1 && n < buf->size - buf->rpos) 61 error("buf_close (short write): %m"); 62 63 } while (n == -1 && (errno == EAGAIN || errno == EINTR)); 64 65 if (n == -1) 66 error("buf_close: %m"); 67 68 free(buf->buf); 69 free(buf); 70 } 71 72 void 73 buf_read(int sock, void *buf, size_t nbytes) 74 { 75 ssize_t n; 76 77 do { 78 n = read(sock, buf, nbytes); 79 if (n == 0) { /* connection closed */ 80 #ifdef DEBUG 81 debug("buf_read (connection closed)"); 82 #endif 83 exit(1); 84 } 85 if (n != -1 && n < nbytes) 86 error("buf_read (short read): %m"); 87 } while (n == -1 && (errno == EINTR || errno == EAGAIN)); 88 89 if (n == -1) 90 error("buf_read: %m"); 91 } 92 93 void 94 dispatch_imsg(int fd) 95 { 96 struct imsg_hdr hdr; 97 char *reason, *filename, 98 *servername, *prefix; 99 size_t reason_len, filename_len, 100 servername_len, prefix_len, totlen; 101 struct client_lease lease; 102 int ret, i, optlen; 103 struct buf *buf; 104 105 buf_read(fd, &hdr, sizeof(hdr)); 106 107 switch (hdr.code) { 108 case IMSG_SCRIPT_INIT: 109 if (hdr.len < sizeof(hdr) + sizeof(size_t)) 110 error("corrupted message received"); 111 buf_read(fd, &reason_len, sizeof(reason_len)); 112 if (hdr.len < reason_len + sizeof(hdr) + sizeof(size_t) || 113 reason_len == SIZE_T_MAX) 114 error("corrupted message received"); 115 if (reason_len > 0) { 116 if ((reason = calloc(1, reason_len + 1)) == NULL) 117 error("%m"); 118 buf_read(fd, reason, reason_len); 119 } else 120 reason = NULL; 121 122 priv_script_init(reason); 123 free(reason); 124 break; 125 case IMSG_SCRIPT_WRITE_PARAMS: 126 bzero(&lease, sizeof lease); 127 totlen = sizeof(hdr) + sizeof(lease) + sizeof(size_t); 128 if (hdr.len < totlen) 129 error("corrupted message received"); 130 buf_read(fd, &lease, sizeof(lease)); 131 132 buf_read(fd, &filename_len, sizeof(filename_len)); 133 totlen += filename_len + sizeof(size_t); 134 if (hdr.len < totlen || filename_len == SIZE_T_MAX) 135 error("corrupted message received"); 136 if (filename_len > 0) { 137 if ((filename = calloc(1, filename_len + 1)) == NULL) 138 error("%m"); 139 buf_read(fd, filename, filename_len); 140 } else 141 filename = NULL; 142 143 buf_read(fd, &servername_len, sizeof(servername_len)); 144 totlen += servername_len + sizeof(size_t); 145 if (hdr.len < totlen || servername_len == SIZE_T_MAX) 146 error("corrupted message received"); 147 if (servername_len > 0) { 148 if ((servername = 149 calloc(1, servername_len + 1)) == NULL) 150 error("%m"); 151 buf_read(fd, servername, servername_len); 152 } else 153 servername = NULL; 154 155 buf_read(fd, &prefix_len, sizeof(prefix_len)); 156 totlen += prefix_len; 157 if (hdr.len < totlen || prefix_len == SIZE_T_MAX) 158 error("corrupted message received"); 159 if (prefix_len > 0) { 160 if ((prefix = calloc(1, prefix_len + 1)) == NULL) 161 error("%m"); 162 buf_read(fd, prefix, prefix_len); 163 } else 164 prefix = NULL; 165 166 for (i = 0; i < 256; i++) { 167 totlen += sizeof(optlen); 168 if (hdr.len < totlen) 169 error("corrupted message received"); 170 buf_read(fd, &optlen, sizeof(optlen)); 171 lease.options[i].data = NULL; 172 lease.options[i].len = optlen; 173 if (optlen > 0) { 174 totlen += optlen; 175 if (hdr.len < totlen || optlen == SIZE_T_MAX) 176 error("corrupted message received"); 177 lease.options[i].data = 178 calloc(1, optlen + 1); 179 if (lease.options[i].data == NULL) 180 error("%m"); 181 buf_read(fd, lease.options[i].data, optlen); 182 } 183 } 184 lease.server_name = servername; 185 lease.filename = filename; 186 187 priv_script_write_params(prefix, &lease); 188 189 free(servername); 190 free(filename); 191 free(prefix); 192 for (i = 0; i < 256; i++) 193 if (lease.options[i].len > 0) 194 free(lease.options[i].data); 195 break; 196 case IMSG_SCRIPT_GO: 197 if (hdr.len != sizeof(hdr)) 198 error("corrupted message received"); 199 200 ret = priv_script_go(); 201 202 hdr.code = IMSG_SCRIPT_GO_RET; 203 hdr.len = sizeof(struct imsg_hdr) + sizeof(int); 204 if ((buf = buf_open(hdr.len)) == NULL) 205 error("buf_open: %m"); 206 buf_add(buf, &hdr, sizeof(hdr)); 207 buf_add(buf, &ret, sizeof(ret)); 208 buf_close(fd, buf); 209 break; 210 default: 211 error("received unknown message, code %d", hdr.code); 212 } 213 } 214