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