Merge branch 'vendor/GMP'
[dragonfly.git] / sbin / dhclient / privsep.c
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 }