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