xref: /freebsd/sbin/dhclient/privsep.c (revision 71c6c44d8d2b62f4e1b6bb5b12fa252314ef116a)
147c08596SBrooks Davis /*	$OpenBSD: privsep.c,v 1.7 2004/05/10 18:34:42 deraadt Exp $ */
247c08596SBrooks Davis 
347c08596SBrooks Davis /*
447c08596SBrooks Davis  * Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
547c08596SBrooks Davis  *
647c08596SBrooks Davis  * Permission to use, copy, modify, and distribute this software for any
747c08596SBrooks Davis  * purpose with or without fee is hereby granted, provided that the above
847c08596SBrooks Davis  * copyright notice and this permission notice appear in all copies.
947c08596SBrooks Davis  *
1047c08596SBrooks Davis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1147c08596SBrooks Davis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1247c08596SBrooks Davis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1347c08596SBrooks Davis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1447c08596SBrooks Davis  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
1547c08596SBrooks Davis  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
1647c08596SBrooks Davis  * OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE.
1747c08596SBrooks Davis  */
1847c08596SBrooks Davis 
198794fdbbSBrooks Davis #include <sys/cdefs.h>
208794fdbbSBrooks Davis __FBSDID("$FreeBSD$");
218794fdbbSBrooks Davis 
2247c08596SBrooks Davis #include "dhcpd.h"
2347c08596SBrooks Davis #include "privsep.h"
2447c08596SBrooks Davis 
2547c08596SBrooks Davis struct buf *
2647c08596SBrooks Davis buf_open(size_t len)
2747c08596SBrooks Davis {
2847c08596SBrooks Davis 	struct buf	*buf;
2947c08596SBrooks Davis 
3047c08596SBrooks Davis 	if ((buf = calloc(1, sizeof(struct buf))) == NULL)
3147c08596SBrooks Davis 		return (NULL);
3247c08596SBrooks Davis 	if ((buf->buf = malloc(len)) == NULL) {
3347c08596SBrooks Davis 		free(buf);
3447c08596SBrooks Davis 		return (NULL);
3547c08596SBrooks Davis 	}
3647c08596SBrooks Davis 	buf->size = len;
3747c08596SBrooks Davis 
3847c08596SBrooks Davis 	return (buf);
3947c08596SBrooks Davis }
4047c08596SBrooks Davis 
4147c08596SBrooks Davis int
4279a1d195SAlan Somers buf_add(struct buf *buf, const void *data, size_t len)
4347c08596SBrooks Davis {
4447c08596SBrooks Davis 	if (buf->wpos + len > buf->size)
4547c08596SBrooks Davis 		return (-1);
4647c08596SBrooks Davis 
4747c08596SBrooks Davis 	memcpy(buf->buf + buf->wpos, data, len);
4847c08596SBrooks Davis 	buf->wpos += len;
4947c08596SBrooks Davis 	return (0);
5047c08596SBrooks Davis }
5147c08596SBrooks Davis 
5247c08596SBrooks Davis int
5347c08596SBrooks Davis buf_close(int sock, struct buf *buf)
5447c08596SBrooks Davis {
5547c08596SBrooks Davis 	ssize_t	n;
5647c08596SBrooks Davis 
5747c08596SBrooks Davis 	do {
5847c08596SBrooks Davis 		n = write(sock, buf->buf + buf->rpos, buf->size - buf->rpos);
5947c08596SBrooks Davis 		if (n != -1)
6047c08596SBrooks Davis 			buf->rpos += n;
6147c08596SBrooks Davis 		if (n == 0) {			/* connection closed */
6247c08596SBrooks Davis 			errno = 0;
6347c08596SBrooks Davis 			return (-1);
6447c08596SBrooks Davis 		}
6547c08596SBrooks Davis 	} while (n == -1 && (errno == EAGAIN || errno == EINTR));
6647c08596SBrooks Davis 
6747c08596SBrooks Davis 	if (buf->rpos < buf->size)
6847c08596SBrooks Davis 		error("short write: wanted %lu got %ld bytes",
6947c08596SBrooks Davis 		    (unsigned long)buf->size, (long)buf->rpos);
7047c08596SBrooks Davis 
7147c08596SBrooks Davis 	free(buf->buf);
7247c08596SBrooks Davis 	free(buf);
7347c08596SBrooks Davis 	return (n);
7447c08596SBrooks Davis }
7547c08596SBrooks Davis 
7647c08596SBrooks Davis ssize_t
7747c08596SBrooks Davis buf_read(int sock, void *buf, size_t nbytes)
7847c08596SBrooks Davis {
79afe6f835SAlan Somers 	ssize_t	n;
80afe6f835SAlan Somers 	size_t r = 0;
8147c08596SBrooks Davis 	char *p = buf;
8247c08596SBrooks Davis 
8347c08596SBrooks Davis 	do {
8447c08596SBrooks Davis 		n = read(sock, p, nbytes);
8547c08596SBrooks Davis 		if (n == 0)
8647c08596SBrooks Davis 			error("connection closed");
8747c08596SBrooks Davis 		if (n != -1) {
88afe6f835SAlan Somers 			r += (size_t)n;
8947c08596SBrooks Davis 			p += n;
9047c08596SBrooks Davis 			nbytes -= n;
9147c08596SBrooks Davis 		}
9247c08596SBrooks Davis 	} while (n == -1 && (errno == EINTR || errno == EAGAIN));
9347c08596SBrooks Davis 
9447c08596SBrooks Davis 	if (n == -1)
9547c08596SBrooks Davis 		error("buf_read: %m");
9647c08596SBrooks Davis 
9747c08596SBrooks Davis 	if (r < nbytes)
9847c08596SBrooks Davis 		error("short read: wanted %lu got %ld bytes",
9947c08596SBrooks Davis 		    (unsigned long)nbytes, (long)r);
10047c08596SBrooks Davis 
10147c08596SBrooks Davis 	return (r);
10247c08596SBrooks Davis }
10347c08596SBrooks Davis 
10447c08596SBrooks Davis void
105*71c6c44dSEitan Adler dispatch_imsg(struct interface_info *ifix, int fd)
10647c08596SBrooks Davis {
10747c08596SBrooks Davis 	struct imsg_hdr		 hdr;
10847c08596SBrooks Davis 	char			*medium, *reason, *filename,
10947c08596SBrooks Davis 				*servername, *prefix;
11047c08596SBrooks Davis 	size_t			 medium_len, reason_len, filename_len,
111afe6f835SAlan Somers 				 servername_len, optlen, prefix_len, totlen;
11247c08596SBrooks Davis 	struct client_lease	 lease;
113afe6f835SAlan Somers 	int			 ret, i;
11447c08596SBrooks Davis 	struct buf		*buf;
115387016a5SConrad Meyer 	u_int16_t		mtu;
11647c08596SBrooks Davis 
11747c08596SBrooks Davis 	buf_read(fd, &hdr, sizeof(hdr));
11847c08596SBrooks Davis 
11947c08596SBrooks Davis 	switch (hdr.code) {
12047c08596SBrooks Davis 	case IMSG_SCRIPT_INIT:
12147c08596SBrooks Davis 		if (hdr.len < sizeof(hdr) + sizeof(size_t))
12247c08596SBrooks Davis 			error("corrupted message received");
12347c08596SBrooks Davis 		buf_read(fd, &medium_len, sizeof(medium_len));
12447c08596SBrooks Davis 		if (hdr.len < medium_len + sizeof(size_t) + sizeof(hdr)
12547c08596SBrooks Davis 		    + sizeof(size_t) || medium_len == SIZE_T_MAX)
12647c08596SBrooks Davis 			error("corrupted message received");
12747c08596SBrooks Davis 		if (medium_len > 0) {
12847c08596SBrooks Davis 			if ((medium = calloc(1, medium_len + 1)) == NULL)
12947c08596SBrooks Davis 				error("%m");
13047c08596SBrooks Davis 			buf_read(fd, medium, medium_len);
13147c08596SBrooks Davis 		} else
13247c08596SBrooks Davis 			medium = NULL;
13347c08596SBrooks Davis 
13447c08596SBrooks Davis 		buf_read(fd, &reason_len, sizeof(reason_len));
13547c08596SBrooks Davis 		if (hdr.len < medium_len + reason_len + sizeof(hdr) ||
13647c08596SBrooks Davis 		    reason_len == SIZE_T_MAX)
13747c08596SBrooks Davis 			error("corrupted message received");
13847c08596SBrooks Davis 		if (reason_len > 0) {
13947c08596SBrooks Davis 			if ((reason = calloc(1, reason_len + 1)) == NULL)
14047c08596SBrooks Davis 				error("%m");
14147c08596SBrooks Davis 			buf_read(fd, reason, reason_len);
14247c08596SBrooks Davis 		} else
14347c08596SBrooks Davis 			reason = NULL;
14447c08596SBrooks Davis 
14547c08596SBrooks Davis 		priv_script_init(reason, medium);
14647c08596SBrooks Davis 		free(reason);
14747c08596SBrooks Davis 		free(medium);
14847c08596SBrooks Davis 		break;
14947c08596SBrooks Davis 	case IMSG_SCRIPT_WRITE_PARAMS:
15047c08596SBrooks Davis 		bzero(&lease, sizeof lease);
15147c08596SBrooks Davis 		totlen = sizeof(hdr) + sizeof(lease) + sizeof(size_t);
15247c08596SBrooks Davis 		if (hdr.len < totlen)
15347c08596SBrooks Davis 			error("corrupted message received");
15447c08596SBrooks Davis 		buf_read(fd, &lease, sizeof(lease));
15547c08596SBrooks Davis 
15647c08596SBrooks Davis 		buf_read(fd, &filename_len, sizeof(filename_len));
15747c08596SBrooks Davis 		totlen += filename_len + sizeof(size_t);
15847c08596SBrooks Davis 		if (hdr.len < totlen || filename_len == SIZE_T_MAX)
15947c08596SBrooks Davis 			error("corrupted message received");
16047c08596SBrooks Davis 		if (filename_len > 0) {
16147c08596SBrooks Davis 			if ((filename = calloc(1, filename_len + 1)) == NULL)
16247c08596SBrooks Davis 				error("%m");
16347c08596SBrooks Davis 			buf_read(fd, filename, filename_len);
16447c08596SBrooks Davis 		} else
16547c08596SBrooks Davis 			filename = NULL;
16647c08596SBrooks Davis 
16747c08596SBrooks Davis 		buf_read(fd, &servername_len, sizeof(servername_len));
16847c08596SBrooks Davis 		totlen += servername_len + sizeof(size_t);
16947c08596SBrooks Davis 		if (hdr.len < totlen || servername_len == SIZE_T_MAX)
17047c08596SBrooks Davis 			error("corrupted message received");
17147c08596SBrooks Davis 		if (servername_len > 0) {
17247c08596SBrooks Davis 			if ((servername =
17347c08596SBrooks Davis 			    calloc(1, servername_len + 1)) == NULL)
17447c08596SBrooks Davis 				error("%m");
17547c08596SBrooks Davis 			buf_read(fd, servername, servername_len);
17647c08596SBrooks Davis 		} else
17747c08596SBrooks Davis 			servername = NULL;
17847c08596SBrooks Davis 
17947c08596SBrooks Davis 		buf_read(fd, &prefix_len, sizeof(prefix_len));
18047c08596SBrooks Davis 		totlen += prefix_len;
18147c08596SBrooks Davis 		if (hdr.len < totlen || prefix_len == SIZE_T_MAX)
18247c08596SBrooks Davis 			error("corrupted message received");
18347c08596SBrooks Davis 		if (prefix_len > 0) {
18447c08596SBrooks Davis 			if ((prefix = calloc(1, prefix_len + 1)) == NULL)
18547c08596SBrooks Davis 				error("%m");
18647c08596SBrooks Davis 			buf_read(fd, prefix, prefix_len);
18747c08596SBrooks Davis 		} else
18847c08596SBrooks Davis 			prefix = NULL;
18947c08596SBrooks Davis 
19047c08596SBrooks Davis 		for (i = 0; i < 256; i++) {
19147c08596SBrooks Davis 			totlen += sizeof(optlen);
19247c08596SBrooks Davis 			if (hdr.len < totlen)
19347c08596SBrooks Davis 				error("corrupted message received");
19447c08596SBrooks Davis 			buf_read(fd, &optlen, sizeof(optlen));
19547c08596SBrooks Davis 			lease.options[i].data = NULL;
19647c08596SBrooks Davis 			lease.options[i].len = optlen;
19747c08596SBrooks Davis 			if (optlen > 0) {
19847c08596SBrooks Davis 				totlen += optlen;
19947c08596SBrooks Davis 				if (hdr.len < totlen || optlen == SIZE_T_MAX)
20047c08596SBrooks Davis 					error("corrupted message received");
20147c08596SBrooks Davis 				lease.options[i].data =
20247c08596SBrooks Davis 				    calloc(1, optlen + 1);
20347c08596SBrooks Davis 				if (lease.options[i].data == NULL)
20447c08596SBrooks Davis 				    error("%m");
20547c08596SBrooks Davis 				buf_read(fd, lease.options[i].data, optlen);
20647c08596SBrooks Davis 			}
20747c08596SBrooks Davis 		}
20847c08596SBrooks Davis 		lease.server_name = servername;
20947c08596SBrooks Davis 		lease.filename = filename;
21047c08596SBrooks Davis 
21147c08596SBrooks Davis 		priv_script_write_params(prefix, &lease);
21247c08596SBrooks Davis 
21347c08596SBrooks Davis 		free(servername);
21447c08596SBrooks Davis 		free(filename);
21547c08596SBrooks Davis 		free(prefix);
21647c08596SBrooks Davis 		for (i = 0; i < 256; i++)
21747c08596SBrooks Davis 			if (lease.options[i].len > 0)
21847c08596SBrooks Davis 				free(lease.options[i].data);
21947c08596SBrooks Davis 		break;
22047c08596SBrooks Davis 	case IMSG_SCRIPT_GO:
22147c08596SBrooks Davis 		if (hdr.len != sizeof(hdr))
22247c08596SBrooks Davis 			error("corrupted message received");
22347c08596SBrooks Davis 
22447c08596SBrooks Davis 		ret = priv_script_go();
22547c08596SBrooks Davis 
22647c08596SBrooks Davis 		hdr.code = IMSG_SCRIPT_GO_RET;
22747c08596SBrooks Davis 		hdr.len = sizeof(struct imsg_hdr) + sizeof(int);
22847c08596SBrooks Davis 		if ((buf = buf_open(hdr.len)) == NULL)
22947c08596SBrooks Davis 			error("buf_open: %m");
23047c08596SBrooks Davis 		if (buf_add(buf, &hdr, sizeof(hdr)))
23147c08596SBrooks Davis 			error("buf_add: %m");
23247c08596SBrooks Davis 		if (buf_add(buf, &ret, sizeof(ret)))
23347c08596SBrooks Davis 			error("buf_add: %m");
23447c08596SBrooks Davis 		if (buf_close(fd, buf) == -1)
23547c08596SBrooks Davis 			error("buf_close: %m");
23647c08596SBrooks Davis 		break;
237235eb530SPawel Jakub Dawidek 	case IMSG_SEND_PACKET:
238*71c6c44dSEitan Adler 		send_packet_priv(ifix, &hdr, fd);
239235eb530SPawel Jakub Dawidek 		break;
240387016a5SConrad Meyer 	case IMSG_SET_INTERFACE_MTU:
241387016a5SConrad Meyer 		if (hdr.len < sizeof(hdr) + sizeof(u_int16_t))
242387016a5SConrad Meyer 			error("corrupted message received");
243387016a5SConrad Meyer 
244387016a5SConrad Meyer 		buf_read(fd, &mtu, sizeof(u_int16_t));
245*71c6c44dSEitan Adler 		interface_set_mtu_priv(ifix->name, mtu);
246387016a5SConrad Meyer 		break;
24747c08596SBrooks Davis 	default:
24847c08596SBrooks Davis 		error("received unknown message, code %d", hdr.code);
24947c08596SBrooks Davis 	}
25047c08596SBrooks Davis }
251