1 /* $OpenBSD: privsep.c,v 1.14 2007/02/15 15:22:27 stevesk 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 *
buf_open(size_t len)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
buf_add(struct buf * buf,void * data,size_t len)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
buf_close(int sock,struct buf * buf)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
buf_read(int sock,void * buf,size_t nbytes)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 debug("buf_read (connection closed)");
81 exit(1);
82 }
83 if (n != -1 && n < nbytes)
84 error("buf_read (short read): %m");
85 } while (n == -1 && (errno == EINTR || errno == EAGAIN));
86
87 if (n == -1)
88 error("buf_read: %m");
89 }
90
91 void
dispatch_imsg(int fd)92 dispatch_imsg(int fd)
93 {
94 struct imsg_hdr hdr;
95 char *medium, *reason, *filename,
96 *servername, *prefix;
97 size_t medium_len, reason_len, filename_len,
98 servername_len, prefix_len, totlen;
99 struct client_lease lease;
100 int ret, i, optlen;
101 struct buf *buf;
102
103 buf_read(fd, &hdr, sizeof(hdr));
104
105 switch (hdr.code) {
106 case IMSG_SCRIPT_INIT:
107 if (hdr.len < sizeof(hdr) + sizeof(size_t))
108 error("corrupted message received");
109 buf_read(fd, &medium_len, sizeof(medium_len));
110 if (hdr.len < medium_len + sizeof(size_t) + sizeof(hdr)
111 + sizeof(size_t) || medium_len == SIZE_T_MAX)
112 error("corrupted message received");
113 if (medium_len > 0) {
114 if ((medium = calloc(1, medium_len + 1)) == NULL)
115 error("%m");
116 buf_read(fd, medium, medium_len);
117 } else
118 medium = NULL;
119
120 buf_read(fd, &reason_len, sizeof(reason_len));
121 if (hdr.len < medium_len + reason_len + sizeof(hdr) ||
122 reason_len == SIZE_T_MAX)
123 error("corrupted message received");
124 if (reason_len > 0) {
125 if ((reason = calloc(1, reason_len + 1)) == NULL)
126 error("%m");
127 buf_read(fd, reason, reason_len);
128 } else
129 reason = NULL;
130
131 priv_script_init(reason, medium);
132 free(reason);
133 free(medium);
134 break;
135 case IMSG_SCRIPT_WRITE_PARAMS:
136 bzero(&lease, sizeof lease);
137 totlen = sizeof(hdr) + sizeof(lease) + sizeof(size_t);
138 if (hdr.len < totlen)
139 error("corrupted message received");
140 buf_read(fd, &lease, sizeof(lease));
141
142 buf_read(fd, &filename_len, sizeof(filename_len));
143 totlen += filename_len + sizeof(size_t);
144 if (hdr.len < totlen || filename_len == SIZE_T_MAX)
145 error("corrupted message received");
146 if (filename_len > 0) {
147 if ((filename = calloc(1, filename_len + 1)) == NULL)
148 error("%m");
149 buf_read(fd, filename, filename_len);
150 } else
151 filename = NULL;
152
153 buf_read(fd, &servername_len, sizeof(servername_len));
154 totlen += servername_len + sizeof(size_t);
155 if (hdr.len < totlen || servername_len == SIZE_T_MAX)
156 error("corrupted message received");
157 if (servername_len > 0) {
158 if ((servername =
159 calloc(1, servername_len + 1)) == NULL)
160 error("%m");
161 buf_read(fd, servername, servername_len);
162 } else
163 servername = NULL;
164
165 buf_read(fd, &prefix_len, sizeof(prefix_len));
166 totlen += prefix_len;
167 if (hdr.len < totlen || prefix_len == SIZE_T_MAX)
168 error("corrupted message received");
169 if (prefix_len > 0) {
170 if ((prefix = calloc(1, prefix_len + 1)) == NULL)
171 error("%m");
172 buf_read(fd, prefix, prefix_len);
173 } else
174 prefix = NULL;
175
176 for (i = 0; i < 256; i++) {
177 totlen += sizeof(optlen);
178 if (hdr.len < totlen)
179 error("corrupted message received");
180 buf_read(fd, &optlen, sizeof(optlen));
181 lease.options[i].data = NULL;
182 lease.options[i].len = optlen;
183 if (optlen > 0) {
184 totlen += optlen;
185 if (hdr.len < totlen || optlen == SIZE_T_MAX)
186 error("corrupted message received");
187 lease.options[i].data =
188 calloc(1, optlen + 1);
189 if (lease.options[i].data == NULL)
190 error("%m");
191 buf_read(fd, lease.options[i].data, optlen);
192 }
193 }
194 lease.server_name = servername;
195 lease.filename = filename;
196
197 priv_script_write_params(prefix, &lease);
198
199 free(servername);
200 free(filename);
201 free(prefix);
202 for (i = 0; i < 256; i++)
203 if (lease.options[i].len > 0)
204 free(lease.options[i].data);
205 break;
206 case IMSG_SCRIPT_GO:
207 if (hdr.len != sizeof(hdr))
208 error("corrupted message received");
209
210 ret = priv_script_go();
211
212 hdr.code = IMSG_SCRIPT_GO_RET;
213 hdr.len = sizeof(struct imsg_hdr) + sizeof(int);
214 if ((buf = buf_open(hdr.len)) == NULL)
215 error("buf_open: %m");
216 buf_add(buf, &hdr, sizeof(hdr));
217 buf_add(buf, &ret, sizeof(ret));
218 buf_close(fd, buf);
219 break;
220 default:
221 error("received unknown message, code %d", hdr.code);
222 }
223 }
224