bb2c2411c04204f968141f952f16b212390d7cfd
[dragonfly.git] / sbin / dhclient / privsep.c
1 /*      $OpenBSD: src/sbin/dhclient/privsep.c,v 1.15 2009/06/06 04:02:42 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                    *medium, *reason, *filename,
98                                 *servername, *prefix;
99         size_t                   medium_len, 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, &medium_len, sizeof(medium_len));
112                 if (hdr.len < medium_len + sizeof(size_t) + sizeof(hdr)
113                     + sizeof(size_t) || medium_len == SIZE_T_MAX)
114                         error("corrupted message received");
115                 if (medium_len > 0) {
116                         if ((medium = calloc(1, medium_len + 1)) == NULL)
117                                 error("%m");
118                         buf_read(fd, medium, medium_len);
119                 } else
120                         medium = NULL;
121
122                 buf_read(fd, &reason_len, sizeof(reason_len));
123                 if (hdr.len < medium_len + reason_len + sizeof(hdr) ||
124                     reason_len == SIZE_T_MAX)
125                         error("corrupted message received");
126                 if (reason_len > 0) {
127                         if ((reason = calloc(1, reason_len + 1)) == NULL)
128                                 error("%m");
129                         buf_read(fd, reason, reason_len);
130                 } else
131                         reason = NULL;
132
133                 priv_script_init(reason, medium);
134                 free(reason);
135                 free(medium);
136                 break;
137         case IMSG_SCRIPT_WRITE_PARAMS:
138                 bzero(&lease, sizeof lease);
139                 totlen = sizeof(hdr) + sizeof(lease) + sizeof(size_t);
140                 if (hdr.len < totlen)
141                         error("corrupted message received");
142                 buf_read(fd, &lease, sizeof(lease));
143
144                 buf_read(fd, &filename_len, sizeof(filename_len));
145                 totlen += filename_len + sizeof(size_t);
146                 if (hdr.len < totlen || filename_len == SIZE_T_MAX)
147                         error("corrupted message received");
148                 if (filename_len > 0) {
149                         if ((filename = calloc(1, filename_len + 1)) == NULL)
150                                 error("%m");
151                         buf_read(fd, filename, filename_len);
152                 } else
153                         filename = NULL;
154
155                 buf_read(fd, &servername_len, sizeof(servername_len));
156                 totlen += servername_len + sizeof(size_t);
157                 if (hdr.len < totlen || servername_len == SIZE_T_MAX)
158                         error("corrupted message received");
159                 if (servername_len > 0) {
160                         if ((servername =
161                             calloc(1, servername_len + 1)) == NULL)
162                                 error("%m");
163                         buf_read(fd, servername, servername_len);
164                 } else
165                         servername = NULL;
166
167                 buf_read(fd, &prefix_len, sizeof(prefix_len));
168                 totlen += prefix_len;
169                 if (hdr.len < totlen || prefix_len == SIZE_T_MAX)
170                         error("corrupted message received");
171                 if (prefix_len > 0) {
172                         if ((prefix = calloc(1, prefix_len + 1)) == NULL)
173                                 error("%m");
174                         buf_read(fd, prefix, prefix_len);
175                 } else
176                         prefix = NULL;
177
178                 for (i = 0; i < 256; i++) {
179                         totlen += sizeof(optlen);
180                         if (hdr.len < totlen)
181                                 error("corrupted message received");
182                         buf_read(fd, &optlen, sizeof(optlen));
183                         lease.options[i].data = NULL;
184                         lease.options[i].len = optlen;
185                         if (optlen > 0) {
186                                 totlen += optlen;
187                                 if (hdr.len < totlen || optlen == SIZE_T_MAX)
188                                         error("corrupted message received");
189                                 lease.options[i].data =
190                                     calloc(1, optlen + 1);
191                                 if (lease.options[i].data == NULL)
192                                     error("%m");
193                                 buf_read(fd, lease.options[i].data, optlen);
194                         }
195                 }
196                 lease.server_name = servername;
197                 lease.filename = filename;
198
199                 priv_script_write_params(prefix, &lease);
200
201                 free(servername);
202                 free(filename);
203                 free(prefix);
204                 for (i = 0; i < 256; i++)
205                         if (lease.options[i].len > 0)
206                                 free(lease.options[i].data);
207                 break;
208         case IMSG_SCRIPT_GO:
209                 if (hdr.len != sizeof(hdr))
210                         error("corrupted message received");
211
212                 ret = priv_script_go();
213
214                 hdr.code = IMSG_SCRIPT_GO_RET;
215                 hdr.len = sizeof(struct imsg_hdr) + sizeof(int);
216                 if ((buf = buf_open(hdr.len)) == NULL)
217                         error("buf_open: %m");
218                 buf_add(buf, &hdr, sizeof(hdr));
219                 buf_add(buf, &ret, sizeof(ret));
220                 buf_close(fd, buf);
221                 break;
222         default:
223                 error("received unknown message, code %d", hdr.code);
224         }
225 }