2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2018 Roy Marples <roy@marples.name>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/socket.h>
51 (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
55 control_queue_purge(struct dhcpcd_ctx *ctx, char *data)
61 /* If no other fd queue has the same data, free it */
63 TAILQ_FOREACH(fp, &ctx->control_fds, next) {
64 TAILQ_FOREACH(fpd, &fp->queue, next) {
65 if (fpd->data == data) {
76 control_queue_free(struct fd_list *fd)
80 while ((fdp = TAILQ_FIRST(&fd->queue))) {
81 TAILQ_REMOVE(&fd->queue, fdp, next);
83 control_queue_purge(fd->ctx, fdp->data);
86 while ((fdp = TAILQ_FIRST(&fd->free_queue))) {
87 TAILQ_REMOVE(&fd->free_queue, fdp, next);
93 control_delete(struct fd_list *fd)
96 TAILQ_REMOVE(&fd->ctx->control_fds, fd, next);
97 eloop_event_delete(fd->ctx->eloop, fd->fd);
99 control_queue_free(fd);
104 control_handle_data(void *arg)
106 struct fd_list *fd = arg;
107 char buffer[1024], *e, *p, *argvp[255], **ap, *a;
112 bytes = read(fd->fd, buffer, sizeof(buffer) - 1);
113 if (bytes == -1 || bytes == 0) {
114 /* Control was closed or there was an error.
115 * Remove it from our list. */
119 buffer[bytes] = '\0';
123 /* Each command is \n terminated
124 * Each argument is NULL separated */
130 if ((size_t)argc >= sizeof(argvp) / sizeof(argvp[0])) {
137 if (len && a[len - 1] == '\n') {
143 if (dhcpcd_handleargs(fd->ctx, fd, argc, argvp) == -1) {
145 if (errno != EINTR && errno != EAGAIN) {
154 control_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags)
156 struct sockaddr_un run;
162 if ((fd = accept(lfd, (struct sockaddr *)&run, &len)) == -1)
164 if ((flags = fcntl(fd, F_GETFD, 0)) == -1 ||
165 fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
170 if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
171 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
176 l = malloc(sizeof(*l));
181 TAILQ_INIT(&l->queue);
182 TAILQ_INIT(&l->free_queue);
183 TAILQ_INSERT_TAIL(&ctx->control_fds, l, next);
184 eloop_event_add(ctx->eloop, l->fd, control_handle_data, l);
190 control_handle(void *arg)
192 struct dhcpcd_ctx *ctx = arg;
194 control_handle1(ctx, ctx->control_fd, 0);
198 control_handle_unpriv(void *arg)
200 struct dhcpcd_ctx *ctx = arg;
202 control_handle1(ctx, ctx->control_unpriv_fd, FD_UNPRIV);
206 make_sock(struct sockaddr_un *sa, const char *ifname, int unpriv)
210 #define SOCK_FLAGS SOCK_CLOEXEC | SOCK_NONBLOCK
211 if ((fd = xsocket(AF_UNIX, SOCK_STREAM | SOCK_FLAGS, 0)) == -1)
214 memset(sa, 0, sizeof(*sa));
215 sa->sun_family = AF_UNIX;
217 strlcpy(sa->sun_path, UNPRIVSOCKET, sizeof(sa->sun_path));
219 snprintf(sa->sun_path, sizeof(sa->sun_path), CONTROLSOCKET,
220 ifname ? "-" : "", ifname ? ifname : "");
225 #define S_PRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
226 #define S_UNPRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
229 control_start1(struct dhcpcd_ctx *ctx, const char *ifname, mode_t fmode)
231 struct sockaddr_un sa;
235 if ((fd = make_sock(&sa, ifname, (fmode & S_UNPRIV) == S_UNPRIV)) == -1)
237 len = (socklen_t)SUN_LEN(&sa);
239 if (bind(fd, (struct sockaddr *)&sa, len) == -1 ||
240 chmod(sa.sun_path, fmode) == -1 ||
241 (ctx->control_group &&
242 chown(sa.sun_path, geteuid(), ctx->control_group) == -1) ||
243 listen(fd, sizeof(ctx->control_fds)) == -1)
250 if ((fmode & S_UNPRIV) != S_UNPRIV)
251 strlcpy(ctx->control_sock, sa.sun_path,
252 sizeof(ctx->control_sock));
257 control_start(struct dhcpcd_ctx *ctx, const char *ifname)
261 if ((fd = control_start1(ctx, ifname, S_PRIV)) == -1)
264 ctx->control_fd = fd;
265 eloop_event_add(ctx->eloop, fd, control_handle, ctx);
267 if (ifname == NULL && (fd = control_start1(ctx, NULL, S_UNPRIV)) != -1){
268 /* We must be in master mode, so create an unpriviledged socket
269 * to allow normal users to learn the status of dhcpcd. */
270 ctx->control_unpriv_fd = fd;
271 eloop_event_add(ctx->eloop, fd, control_handle_unpriv, ctx);
273 return ctx->control_fd;
277 control_stop(struct dhcpcd_ctx *ctx)
282 if (ctx->options & DHCPCD_FORKED)
285 if (ctx->control_fd == -1)
287 eloop_event_delete(ctx->eloop, ctx->control_fd);
288 close(ctx->control_fd);
289 ctx->control_fd = -1;
290 if (unlink(ctx->control_sock) == -1)
293 if (ctx->control_unpriv_fd != -1) {
294 eloop_event_delete(ctx->eloop, ctx->control_unpriv_fd);
295 close(ctx->control_unpriv_fd);
296 ctx->control_unpriv_fd = -1;
297 if (unlink(UNPRIVSOCKET) == -1)
302 while ((l = TAILQ_FIRST(&ctx->control_fds))) {
303 TAILQ_REMOVE(&ctx->control_fds, l, next);
304 eloop_event_delete(ctx->eloop, l->fd);
306 control_queue_free(l);
314 control_open(const char *ifname)
316 struct sockaddr_un sa;
319 if ((fd = make_sock(&sa, ifname, 0)) != -1) {
322 len = (socklen_t)SUN_LEN(&sa);
323 if (connect(fd, (struct sockaddr *)&sa, len) == -1) {
332 control_send(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
343 for (i = 0; i < argc; i++) {
344 l = strlen(argv[i]) + 1;
345 if (len + l > sizeof(buffer)) {
349 memcpy(buffer + len, argv[i], l);
352 return write(ctx->control_fd, buffer, len);
356 control_writeone(void *arg)
360 struct fd_data *data;
363 data = TAILQ_FIRST(&fd->queue);
364 iov[0].iov_base = &data->data_len;
365 iov[0].iov_len = sizeof(size_t);
366 iov[1].iov_base = data->data;
367 iov[1].iov_len = data->data_len;
368 if (writev(fd->fd, iov, 2) == -1) {
370 if (errno != EINTR && errno != EAGAIN)
375 TAILQ_REMOVE(&fd->queue, data, next);
377 control_queue_purge(fd->ctx, data->data);
378 data->data = NULL; /* safety */
380 TAILQ_INSERT_TAIL(&fd->free_queue, data, next);
382 if (TAILQ_FIRST(&fd->queue) == NULL)
383 eloop_event_remove_writecb(fd->ctx->eloop, fd->fd);
387 control_queue(struct fd_list *fd, char *data, size_t data_len, uint8_t fit)
392 d = TAILQ_FIRST(&fd->free_queue);
394 TAILQ_REMOVE(&fd->free_queue, d, next);
397 TAILQ_FOREACH(d, &fd->queue, next) {
398 if (++n == CONTROL_QUEUE_MAX) {
403 d = malloc(sizeof(*d));
408 d->data_len = data_len;
410 TAILQ_INSERT_TAIL(&fd->queue, d, next);
411 eloop_event_add_w(fd->ctx->eloop, fd->fd, control_writeone, fd);
416 control_close(struct dhcpcd_ctx *ctx)
419 if (ctx->control_fd != -1) {
420 close(ctx->control_fd);
421 ctx->control_fd = -1;