libc/regex: fix two buffer underruns.
[freebsd-src.git] / sbin / dhclient / privsep.c
bloba0521a6cc24bd92039fa3483439c74346cd70e52
1 /* $OpenBSD: privsep.c,v 1.7 2004/05/10 18:34:42 deraadt Exp $ */
3 /*
4 * Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
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.
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.
19 #include <sys/cdefs.h>
20 __FBSDID("$FreeBSD$");
22 #include "dhcpd.h"
23 #include "privsep.h"
25 struct buf *
26 buf_open(size_t len)
28 struct buf *buf;
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);
36 buf->size = len;
38 return (buf);
41 int
42 buf_add(struct buf *buf, void *data, size_t len)
44 if (buf->wpos + len > buf->size)
45 return (-1);
47 memcpy(buf->buf + buf->wpos, data, len);
48 buf->wpos += len;
49 return (0);
52 int
53 buf_close(int sock, struct buf *buf)
55 ssize_t n;
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);
65 } while (n == -1 && (errno == EAGAIN || errno == EINTR));
67 if (buf->rpos < buf->size)
68 error("short write: wanted %lu got %ld bytes",
69 (unsigned long)buf->size, (long)buf->rpos);
71 free(buf->buf);
72 free(buf);
73 return (n);
76 ssize_t
77 buf_read(int sock, void *buf, size_t nbytes)
79 ssize_t n, r = 0;
80 char *p = buf;
82 do {
83 n = read(sock, p, nbytes);
84 if (n == 0)
85 error("connection closed");
86 if (n != -1) {
87 r += n;
88 p += n;
89 nbytes -= n;
91 } while (n == -1 && (errno == EINTR || errno == EAGAIN));
93 if (n == -1)
94 error("buf_read: %m");
96 if (r < nbytes)
97 error("short read: wanted %lu got %ld bytes",
98 (unsigned long)nbytes, (long)r);
100 return (r);
103 void
104 dispatch_imsg(struct interface_info *ifi, int fd)
106 struct imsg_hdr hdr;
107 char *medium, *reason, *filename,
108 *servername, *prefix;
109 size_t medium_len, reason_len, filename_len,
110 servername_len, prefix_len, totlen;
111 struct client_lease lease;
112 int ret, i, optlen;
113 struct buf *buf;
115 buf_read(fd, &hdr, sizeof(hdr));
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;
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;
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));
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;
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;
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;
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);
206 lease.server_name = servername;
207 lease.filename = filename;
209 priv_script_write_params(prefix, &lease);
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");
222 ret = priv_script_go();
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(ifi, &hdr, fd);
237 break;
238 default:
239 error("received unknown message, code %d", hdr.code);