xref: /dragonfly/sbin/dhclient/privsep.c (revision 277a81d9fe2047f1a89439c4bc1659f09a1cdea0)
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 *
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 #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
dispatch_imsg(int fd)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