xref: /dragonfly/sbin/dhclient/privsep.c (revision 36a3d1d6)
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