1*9f20bfa6SDavid van Moolenbroek #include <sys/cdefs.h>
2*9f20bfa6SDavid van Moolenbroek __RCSID("$NetBSD: control.c,v 1.10 2015/08/21 10:39:00 roy Exp $");
3*9f20bfa6SDavid van Moolenbroek
4*9f20bfa6SDavid van Moolenbroek /*
5*9f20bfa6SDavid van Moolenbroek * dhcpcd - DHCP client daemon
6*9f20bfa6SDavid van Moolenbroek * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
7*9f20bfa6SDavid van Moolenbroek * All rights reserved
8*9f20bfa6SDavid van Moolenbroek
9*9f20bfa6SDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
10*9f20bfa6SDavid van Moolenbroek * modification, are permitted provided that the following conditions
11*9f20bfa6SDavid van Moolenbroek * are met:
12*9f20bfa6SDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
13*9f20bfa6SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
14*9f20bfa6SDavid van Moolenbroek * 2. Redistributions in binary form must reproduce the above copyright
15*9f20bfa6SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer in the
16*9f20bfa6SDavid van Moolenbroek * documentation and/or other materials provided with the distribution.
17*9f20bfa6SDavid van Moolenbroek *
18*9f20bfa6SDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19*9f20bfa6SDavid van Moolenbroek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*9f20bfa6SDavid van Moolenbroek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*9f20bfa6SDavid van Moolenbroek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*9f20bfa6SDavid van Moolenbroek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*9f20bfa6SDavid van Moolenbroek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*9f20bfa6SDavid van Moolenbroek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*9f20bfa6SDavid van Moolenbroek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*9f20bfa6SDavid van Moolenbroek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*9f20bfa6SDavid van Moolenbroek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*9f20bfa6SDavid van Moolenbroek * SUCH DAMAGE.
29*9f20bfa6SDavid van Moolenbroek */
30*9f20bfa6SDavid van Moolenbroek
31*9f20bfa6SDavid van Moolenbroek #include <sys/socket.h>
32*9f20bfa6SDavid van Moolenbroek #include <sys/stat.h>
33*9f20bfa6SDavid van Moolenbroek #include <sys/uio.h>
34*9f20bfa6SDavid van Moolenbroek #include <sys/un.h>
35*9f20bfa6SDavid van Moolenbroek
36*9f20bfa6SDavid van Moolenbroek #include <errno.h>
37*9f20bfa6SDavid van Moolenbroek #include <fcntl.h>
38*9f20bfa6SDavid van Moolenbroek #include <stdio.h>
39*9f20bfa6SDavid van Moolenbroek #include <stdlib.h>
40*9f20bfa6SDavid van Moolenbroek #include <string.h>
41*9f20bfa6SDavid van Moolenbroek #include <time.h>
42*9f20bfa6SDavid van Moolenbroek #include <unistd.h>
43*9f20bfa6SDavid van Moolenbroek
44*9f20bfa6SDavid van Moolenbroek #include "config.h"
45*9f20bfa6SDavid van Moolenbroek #include "common.h"
46*9f20bfa6SDavid van Moolenbroek #include "dhcpcd.h"
47*9f20bfa6SDavid van Moolenbroek #include "control.h"
48*9f20bfa6SDavid van Moolenbroek #include "eloop.h"
49*9f20bfa6SDavid van Moolenbroek #include "if.h"
50*9f20bfa6SDavid van Moolenbroek
51*9f20bfa6SDavid van Moolenbroek #ifndef SUN_LEN
52*9f20bfa6SDavid van Moolenbroek #define SUN_LEN(su) \
53*9f20bfa6SDavid van Moolenbroek (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
54*9f20bfa6SDavid van Moolenbroek #endif
55*9f20bfa6SDavid van Moolenbroek
56*9f20bfa6SDavid van Moolenbroek static void
control_queue_purge(struct dhcpcd_ctx * ctx,char * data)57*9f20bfa6SDavid van Moolenbroek control_queue_purge(struct dhcpcd_ctx *ctx, char *data)
58*9f20bfa6SDavid van Moolenbroek {
59*9f20bfa6SDavid van Moolenbroek int found;
60*9f20bfa6SDavid van Moolenbroek struct fd_list *fp;
61*9f20bfa6SDavid van Moolenbroek struct fd_data *fpd;
62*9f20bfa6SDavid van Moolenbroek
63*9f20bfa6SDavid van Moolenbroek /* If no other fd queue has the same data, free it */
64*9f20bfa6SDavid van Moolenbroek found = 0;
65*9f20bfa6SDavid van Moolenbroek TAILQ_FOREACH(fp, &ctx->control_fds, next) {
66*9f20bfa6SDavid van Moolenbroek TAILQ_FOREACH(fpd, &fp->queue, next) {
67*9f20bfa6SDavid van Moolenbroek if (fpd->data == data) {
68*9f20bfa6SDavid van Moolenbroek found = 1;
69*9f20bfa6SDavid van Moolenbroek break;
70*9f20bfa6SDavid van Moolenbroek }
71*9f20bfa6SDavid van Moolenbroek }
72*9f20bfa6SDavid van Moolenbroek }
73*9f20bfa6SDavid van Moolenbroek if (!found)
74*9f20bfa6SDavid van Moolenbroek free(data);
75*9f20bfa6SDavid van Moolenbroek }
76*9f20bfa6SDavid van Moolenbroek
77*9f20bfa6SDavid van Moolenbroek static void
control_queue_free(struct fd_list * fd)78*9f20bfa6SDavid van Moolenbroek control_queue_free(struct fd_list *fd)
79*9f20bfa6SDavid van Moolenbroek {
80*9f20bfa6SDavid van Moolenbroek struct fd_data *fdp;
81*9f20bfa6SDavid van Moolenbroek
82*9f20bfa6SDavid van Moolenbroek while ((fdp = TAILQ_FIRST(&fd->queue))) {
83*9f20bfa6SDavid van Moolenbroek TAILQ_REMOVE(&fd->queue, fdp, next);
84*9f20bfa6SDavid van Moolenbroek if (fdp->freeit)
85*9f20bfa6SDavid van Moolenbroek control_queue_purge(fd->ctx, fdp->data);
86*9f20bfa6SDavid van Moolenbroek free(fdp);
87*9f20bfa6SDavid van Moolenbroek }
88*9f20bfa6SDavid van Moolenbroek while ((fdp = TAILQ_FIRST(&fd->free_queue))) {
89*9f20bfa6SDavid van Moolenbroek TAILQ_REMOVE(&fd->free_queue, fdp, next);
90*9f20bfa6SDavid van Moolenbroek free(fdp);
91*9f20bfa6SDavid van Moolenbroek }
92*9f20bfa6SDavid van Moolenbroek }
93*9f20bfa6SDavid van Moolenbroek
94*9f20bfa6SDavid van Moolenbroek static void
control_delete(struct fd_list * fd)95*9f20bfa6SDavid van Moolenbroek control_delete(struct fd_list *fd)
96*9f20bfa6SDavid van Moolenbroek {
97*9f20bfa6SDavid van Moolenbroek
98*9f20bfa6SDavid van Moolenbroek TAILQ_REMOVE(&fd->ctx->control_fds, fd, next);
99*9f20bfa6SDavid van Moolenbroek eloop_event_delete(fd->ctx->eloop, fd->fd);
100*9f20bfa6SDavid van Moolenbroek close(fd->fd);
101*9f20bfa6SDavid van Moolenbroek control_queue_free(fd);
102*9f20bfa6SDavid van Moolenbroek free(fd);
103*9f20bfa6SDavid van Moolenbroek }
104*9f20bfa6SDavid van Moolenbroek
105*9f20bfa6SDavid van Moolenbroek static void
control_handle_data(void * arg)106*9f20bfa6SDavid van Moolenbroek control_handle_data(void *arg)
107*9f20bfa6SDavid van Moolenbroek {
108*9f20bfa6SDavid van Moolenbroek struct fd_list *fd = arg;
109*9f20bfa6SDavid van Moolenbroek char buffer[1024], *e, *p, *argvp[255], **ap, *a;
110*9f20bfa6SDavid van Moolenbroek ssize_t bytes;
111*9f20bfa6SDavid van Moolenbroek size_t len;
112*9f20bfa6SDavid van Moolenbroek int argc;
113*9f20bfa6SDavid van Moolenbroek
114*9f20bfa6SDavid van Moolenbroek bytes = read(fd->fd, buffer, sizeof(buffer) - 1);
115*9f20bfa6SDavid van Moolenbroek if (bytes == -1 || bytes == 0) {
116*9f20bfa6SDavid van Moolenbroek /* Control was closed or there was an error.
117*9f20bfa6SDavid van Moolenbroek * Remove it from our list. */
118*9f20bfa6SDavid van Moolenbroek control_delete(fd);
119*9f20bfa6SDavid van Moolenbroek return;
120*9f20bfa6SDavid van Moolenbroek }
121*9f20bfa6SDavid van Moolenbroek buffer[bytes] = '\0';
122*9f20bfa6SDavid van Moolenbroek p = buffer;
123*9f20bfa6SDavid van Moolenbroek e = buffer + bytes;
124*9f20bfa6SDavid van Moolenbroek
125*9f20bfa6SDavid van Moolenbroek /* Each command is \n terminated
126*9f20bfa6SDavid van Moolenbroek * Each argument is NULL separated */
127*9f20bfa6SDavid van Moolenbroek while (p < e) {
128*9f20bfa6SDavid van Moolenbroek argc = 0;
129*9f20bfa6SDavid van Moolenbroek ap = argvp;
130*9f20bfa6SDavid van Moolenbroek while (p < e) {
131*9f20bfa6SDavid van Moolenbroek argc++;
132*9f20bfa6SDavid van Moolenbroek if ((size_t)argc >= sizeof(argvp) / sizeof(argvp[0])) {
133*9f20bfa6SDavid van Moolenbroek errno = ENOBUFS;
134*9f20bfa6SDavid van Moolenbroek return;
135*9f20bfa6SDavid van Moolenbroek }
136*9f20bfa6SDavid van Moolenbroek a = *ap++ = p;
137*9f20bfa6SDavid van Moolenbroek len = strlen(p);
138*9f20bfa6SDavid van Moolenbroek p += len + 1;
139*9f20bfa6SDavid van Moolenbroek if (len && a[len - 1] == '\n') {
140*9f20bfa6SDavid van Moolenbroek a[len - 1] = '\0';
141*9f20bfa6SDavid van Moolenbroek break;
142*9f20bfa6SDavid van Moolenbroek }
143*9f20bfa6SDavid van Moolenbroek }
144*9f20bfa6SDavid van Moolenbroek *ap = NULL;
145*9f20bfa6SDavid van Moolenbroek if (dhcpcd_handleargs(fd->ctx, fd, argc, argvp) == -1) {
146*9f20bfa6SDavid van Moolenbroek logger(fd->ctx, LOG_ERR,
147*9f20bfa6SDavid van Moolenbroek "%s: dhcpcd_handleargs: %m", __func__);
148*9f20bfa6SDavid van Moolenbroek if (errno != EINTR && errno != EAGAIN) {
149*9f20bfa6SDavid van Moolenbroek control_delete(fd);
150*9f20bfa6SDavid van Moolenbroek return;
151*9f20bfa6SDavid van Moolenbroek }
152*9f20bfa6SDavid van Moolenbroek }
153*9f20bfa6SDavid van Moolenbroek }
154*9f20bfa6SDavid van Moolenbroek }
155*9f20bfa6SDavid van Moolenbroek
156*9f20bfa6SDavid van Moolenbroek static void
control_handle1(struct dhcpcd_ctx * ctx,int lfd,unsigned int fd_flags)157*9f20bfa6SDavid van Moolenbroek control_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags)
158*9f20bfa6SDavid van Moolenbroek {
159*9f20bfa6SDavid van Moolenbroek struct sockaddr_un run;
160*9f20bfa6SDavid van Moolenbroek socklen_t len;
161*9f20bfa6SDavid van Moolenbroek struct fd_list *l;
162*9f20bfa6SDavid van Moolenbroek int fd, flags;
163*9f20bfa6SDavid van Moolenbroek
164*9f20bfa6SDavid van Moolenbroek len = sizeof(run);
165*9f20bfa6SDavid van Moolenbroek if ((fd = accept(lfd, (struct sockaddr *)&run, &len)) == -1)
166*9f20bfa6SDavid van Moolenbroek return;
167*9f20bfa6SDavid van Moolenbroek if ((flags = fcntl(fd, F_GETFD, 0)) == -1 ||
168*9f20bfa6SDavid van Moolenbroek fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
169*9f20bfa6SDavid van Moolenbroek {
170*9f20bfa6SDavid van Moolenbroek close(fd);
171*9f20bfa6SDavid van Moolenbroek return;
172*9f20bfa6SDavid van Moolenbroek }
173*9f20bfa6SDavid van Moolenbroek if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
174*9f20bfa6SDavid van Moolenbroek fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
175*9f20bfa6SDavid van Moolenbroek {
176*9f20bfa6SDavid van Moolenbroek close(fd);
177*9f20bfa6SDavid van Moolenbroek return;
178*9f20bfa6SDavid van Moolenbroek }
179*9f20bfa6SDavid van Moolenbroek l = malloc(sizeof(*l));
180*9f20bfa6SDavid van Moolenbroek if (l) {
181*9f20bfa6SDavid van Moolenbroek l->ctx = ctx;
182*9f20bfa6SDavid van Moolenbroek l->fd = fd;
183*9f20bfa6SDavid van Moolenbroek l->flags = fd_flags;
184*9f20bfa6SDavid van Moolenbroek TAILQ_INIT(&l->queue);
185*9f20bfa6SDavid van Moolenbroek TAILQ_INIT(&l->free_queue);
186*9f20bfa6SDavid van Moolenbroek TAILQ_INSERT_TAIL(&ctx->control_fds, l, next);
187*9f20bfa6SDavid van Moolenbroek eloop_event_add(ctx->eloop, l->fd,
188*9f20bfa6SDavid van Moolenbroek control_handle_data, l, NULL, NULL);
189*9f20bfa6SDavid van Moolenbroek } else
190*9f20bfa6SDavid van Moolenbroek close(fd);
191*9f20bfa6SDavid van Moolenbroek }
192*9f20bfa6SDavid van Moolenbroek
193*9f20bfa6SDavid van Moolenbroek static void
control_handle(void * arg)194*9f20bfa6SDavid van Moolenbroek control_handle(void *arg)
195*9f20bfa6SDavid van Moolenbroek {
196*9f20bfa6SDavid van Moolenbroek struct dhcpcd_ctx *ctx = arg;
197*9f20bfa6SDavid van Moolenbroek
198*9f20bfa6SDavid van Moolenbroek control_handle1(ctx, ctx->control_fd, 0);
199*9f20bfa6SDavid van Moolenbroek }
200*9f20bfa6SDavid van Moolenbroek
201*9f20bfa6SDavid van Moolenbroek static void
control_handle_unpriv(void * arg)202*9f20bfa6SDavid van Moolenbroek control_handle_unpriv(void *arg)
203*9f20bfa6SDavid van Moolenbroek {
204*9f20bfa6SDavid van Moolenbroek struct dhcpcd_ctx *ctx = arg;
205*9f20bfa6SDavid van Moolenbroek
206*9f20bfa6SDavid van Moolenbroek control_handle1(ctx, ctx->control_unpriv_fd, FD_UNPRIV);
207*9f20bfa6SDavid van Moolenbroek }
208*9f20bfa6SDavid van Moolenbroek
209*9f20bfa6SDavid van Moolenbroek static int
make_sock(struct sockaddr_un * sa,const char * ifname,int unpriv)210*9f20bfa6SDavid van Moolenbroek make_sock(struct sockaddr_un *sa, const char *ifname, int unpriv)
211*9f20bfa6SDavid van Moolenbroek {
212*9f20bfa6SDavid van Moolenbroek int fd;
213*9f20bfa6SDavid van Moolenbroek
214*9f20bfa6SDavid van Moolenbroek if ((fd = xsocket(AF_UNIX, SOCK_STREAM, 0, O_NONBLOCK|O_CLOEXEC)) == -1)
215*9f20bfa6SDavid van Moolenbroek return -1;
216*9f20bfa6SDavid van Moolenbroek memset(sa, 0, sizeof(*sa));
217*9f20bfa6SDavid van Moolenbroek sa->sun_family = AF_UNIX;
218*9f20bfa6SDavid van Moolenbroek if (unpriv)
219*9f20bfa6SDavid van Moolenbroek strlcpy(sa->sun_path, UNPRIVSOCKET, sizeof(sa->sun_path));
220*9f20bfa6SDavid van Moolenbroek else {
221*9f20bfa6SDavid van Moolenbroek snprintf(sa->sun_path, sizeof(sa->sun_path), CONTROLSOCKET,
222*9f20bfa6SDavid van Moolenbroek ifname ? "-" : "", ifname ? ifname : "");
223*9f20bfa6SDavid van Moolenbroek }
224*9f20bfa6SDavid van Moolenbroek return fd;
225*9f20bfa6SDavid van Moolenbroek }
226*9f20bfa6SDavid van Moolenbroek
227*9f20bfa6SDavid van Moolenbroek #define S_PRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
228*9f20bfa6SDavid van Moolenbroek #define S_UNPRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
229*9f20bfa6SDavid van Moolenbroek
230*9f20bfa6SDavid van Moolenbroek static int
control_start1(struct dhcpcd_ctx * ctx,const char * ifname,mode_t fmode)231*9f20bfa6SDavid van Moolenbroek control_start1(struct dhcpcd_ctx *ctx, const char *ifname, mode_t fmode)
232*9f20bfa6SDavid van Moolenbroek {
233*9f20bfa6SDavid van Moolenbroek struct sockaddr_un sa;
234*9f20bfa6SDavid van Moolenbroek int fd;
235*9f20bfa6SDavid van Moolenbroek socklen_t len;
236*9f20bfa6SDavid van Moolenbroek
237*9f20bfa6SDavid van Moolenbroek if ((fd = make_sock(&sa, ifname, (fmode & S_UNPRIV) == S_UNPRIV)) == -1)
238*9f20bfa6SDavid van Moolenbroek return -1;
239*9f20bfa6SDavid van Moolenbroek len = (socklen_t)SUN_LEN(&sa);
240*9f20bfa6SDavid van Moolenbroek unlink(sa.sun_path);
241*9f20bfa6SDavid van Moolenbroek if (bind(fd, (struct sockaddr *)&sa, len) == -1 ||
242*9f20bfa6SDavid van Moolenbroek chmod(sa.sun_path, fmode) == -1 ||
243*9f20bfa6SDavid van Moolenbroek (ctx->control_group &&
244*9f20bfa6SDavid van Moolenbroek chown(sa.sun_path, geteuid(), ctx->control_group) == -1) ||
245*9f20bfa6SDavid van Moolenbroek listen(fd, sizeof(ctx->control_fds)) == -1)
246*9f20bfa6SDavid van Moolenbroek {
247*9f20bfa6SDavid van Moolenbroek close(fd);
248*9f20bfa6SDavid van Moolenbroek unlink(sa.sun_path);
249*9f20bfa6SDavid van Moolenbroek return -1;
250*9f20bfa6SDavid van Moolenbroek }
251*9f20bfa6SDavid van Moolenbroek
252*9f20bfa6SDavid van Moolenbroek if ((fmode & S_UNPRIV) != S_UNPRIV)
253*9f20bfa6SDavid van Moolenbroek strlcpy(ctx->control_sock, sa.sun_path,
254*9f20bfa6SDavid van Moolenbroek sizeof(ctx->control_sock));
255*9f20bfa6SDavid van Moolenbroek return fd;
256*9f20bfa6SDavid van Moolenbroek }
257*9f20bfa6SDavid van Moolenbroek
258*9f20bfa6SDavid van Moolenbroek int
control_start(struct dhcpcd_ctx * ctx,const char * ifname)259*9f20bfa6SDavid van Moolenbroek control_start(struct dhcpcd_ctx *ctx, const char *ifname)
260*9f20bfa6SDavid van Moolenbroek {
261*9f20bfa6SDavid van Moolenbroek int fd;
262*9f20bfa6SDavid van Moolenbroek
263*9f20bfa6SDavid van Moolenbroek if ((fd = control_start1(ctx, ifname, S_PRIV)) == -1)
264*9f20bfa6SDavid van Moolenbroek return -1;
265*9f20bfa6SDavid van Moolenbroek
266*9f20bfa6SDavid van Moolenbroek ctx->control_fd = fd;
267*9f20bfa6SDavid van Moolenbroek eloop_event_add(ctx->eloop, fd, control_handle, ctx, NULL, NULL);
268*9f20bfa6SDavid van Moolenbroek
269*9f20bfa6SDavid van Moolenbroek if (ifname == NULL && (fd = control_start1(ctx, NULL, S_UNPRIV)) != -1){
270*9f20bfa6SDavid van Moolenbroek /* We must be in master mode, so create an unpriviledged socket
271*9f20bfa6SDavid van Moolenbroek * to allow normal users to learn the status of dhcpcd. */
272*9f20bfa6SDavid van Moolenbroek ctx->control_unpriv_fd = fd;
273*9f20bfa6SDavid van Moolenbroek eloop_event_add(ctx->eloop, fd, control_handle_unpriv,
274*9f20bfa6SDavid van Moolenbroek ctx, NULL, NULL);
275*9f20bfa6SDavid van Moolenbroek }
276*9f20bfa6SDavid van Moolenbroek return ctx->control_fd;
277*9f20bfa6SDavid van Moolenbroek }
278*9f20bfa6SDavid van Moolenbroek
279*9f20bfa6SDavid van Moolenbroek int
control_stop(struct dhcpcd_ctx * ctx)280*9f20bfa6SDavid van Moolenbroek control_stop(struct dhcpcd_ctx *ctx)
281*9f20bfa6SDavid van Moolenbroek {
282*9f20bfa6SDavid van Moolenbroek int retval = 0;
283*9f20bfa6SDavid van Moolenbroek struct fd_list *l;
284*9f20bfa6SDavid van Moolenbroek
285*9f20bfa6SDavid van Moolenbroek if (ctx->options & DHCPCD_FORKED)
286*9f20bfa6SDavid van Moolenbroek goto freeit;
287*9f20bfa6SDavid van Moolenbroek
288*9f20bfa6SDavid van Moolenbroek if (ctx->control_fd == -1)
289*9f20bfa6SDavid van Moolenbroek return 0;
290*9f20bfa6SDavid van Moolenbroek eloop_event_delete(ctx->eloop, ctx->control_fd);
291*9f20bfa6SDavid van Moolenbroek close(ctx->control_fd);
292*9f20bfa6SDavid van Moolenbroek ctx->control_fd = -1;
293*9f20bfa6SDavid van Moolenbroek if (unlink(ctx->control_sock) == -1)
294*9f20bfa6SDavid van Moolenbroek retval = -1;
295*9f20bfa6SDavid van Moolenbroek
296*9f20bfa6SDavid van Moolenbroek if (ctx->control_unpriv_fd != -1) {
297*9f20bfa6SDavid van Moolenbroek eloop_event_delete(ctx->eloop, ctx->control_unpriv_fd);
298*9f20bfa6SDavid van Moolenbroek close(ctx->control_unpriv_fd);
299*9f20bfa6SDavid van Moolenbroek ctx->control_unpriv_fd = -1;
300*9f20bfa6SDavid van Moolenbroek if (unlink(UNPRIVSOCKET) == -1)
301*9f20bfa6SDavid van Moolenbroek retval = -1;
302*9f20bfa6SDavid van Moolenbroek }
303*9f20bfa6SDavid van Moolenbroek
304*9f20bfa6SDavid van Moolenbroek freeit:
305*9f20bfa6SDavid van Moolenbroek while ((l = TAILQ_FIRST(&ctx->control_fds))) {
306*9f20bfa6SDavid van Moolenbroek TAILQ_REMOVE(&ctx->control_fds, l, next);
307*9f20bfa6SDavid van Moolenbroek eloop_event_delete(ctx->eloop, l->fd);
308*9f20bfa6SDavid van Moolenbroek close(l->fd);
309*9f20bfa6SDavid van Moolenbroek control_queue_free(l);
310*9f20bfa6SDavid van Moolenbroek free(l);
311*9f20bfa6SDavid van Moolenbroek }
312*9f20bfa6SDavid van Moolenbroek
313*9f20bfa6SDavid van Moolenbroek return retval;
314*9f20bfa6SDavid van Moolenbroek }
315*9f20bfa6SDavid van Moolenbroek
316*9f20bfa6SDavid van Moolenbroek int
control_open(struct dhcpcd_ctx * ctx,const char * ifname)317*9f20bfa6SDavid van Moolenbroek control_open(struct dhcpcd_ctx *ctx, const char *ifname)
318*9f20bfa6SDavid van Moolenbroek {
319*9f20bfa6SDavid van Moolenbroek struct sockaddr_un sa;
320*9f20bfa6SDavid van Moolenbroek socklen_t len;
321*9f20bfa6SDavid van Moolenbroek
322*9f20bfa6SDavid van Moolenbroek if ((ctx->control_fd = make_sock(&sa, ifname, 0)) == -1)
323*9f20bfa6SDavid van Moolenbroek return -1;
324*9f20bfa6SDavid van Moolenbroek len = (socklen_t)SUN_LEN(&sa);
325*9f20bfa6SDavid van Moolenbroek if (connect(ctx->control_fd, (struct sockaddr *)&sa, len) == -1) {
326*9f20bfa6SDavid van Moolenbroek close(ctx->control_fd);
327*9f20bfa6SDavid van Moolenbroek ctx->control_fd = -1;
328*9f20bfa6SDavid van Moolenbroek return -1;
329*9f20bfa6SDavid van Moolenbroek }
330*9f20bfa6SDavid van Moolenbroek return 0;
331*9f20bfa6SDavid van Moolenbroek }
332*9f20bfa6SDavid van Moolenbroek
333*9f20bfa6SDavid van Moolenbroek ssize_t
control_send(struct dhcpcd_ctx * ctx,int argc,char * const * argv)334*9f20bfa6SDavid van Moolenbroek control_send(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
335*9f20bfa6SDavid van Moolenbroek {
336*9f20bfa6SDavid van Moolenbroek char buffer[1024];
337*9f20bfa6SDavid van Moolenbroek int i;
338*9f20bfa6SDavid van Moolenbroek size_t len, l;
339*9f20bfa6SDavid van Moolenbroek
340*9f20bfa6SDavid van Moolenbroek if (argc > 255) {
341*9f20bfa6SDavid van Moolenbroek errno = ENOBUFS;
342*9f20bfa6SDavid van Moolenbroek return -1;
343*9f20bfa6SDavid van Moolenbroek }
344*9f20bfa6SDavid van Moolenbroek len = 0;
345*9f20bfa6SDavid van Moolenbroek for (i = 0; i < argc; i++) {
346*9f20bfa6SDavid van Moolenbroek l = strlen(argv[i]) + 1;
347*9f20bfa6SDavid van Moolenbroek if (len + l > sizeof(buffer)) {
348*9f20bfa6SDavid van Moolenbroek errno = ENOBUFS;
349*9f20bfa6SDavid van Moolenbroek return -1;
350*9f20bfa6SDavid van Moolenbroek }
351*9f20bfa6SDavid van Moolenbroek memcpy(buffer + len, argv[i], l);
352*9f20bfa6SDavid van Moolenbroek len += l;
353*9f20bfa6SDavid van Moolenbroek }
354*9f20bfa6SDavid van Moolenbroek return write(ctx->control_fd, buffer, len);
355*9f20bfa6SDavid van Moolenbroek }
356*9f20bfa6SDavid van Moolenbroek
357*9f20bfa6SDavid van Moolenbroek static void
control_writeone(void * arg)358*9f20bfa6SDavid van Moolenbroek control_writeone(void *arg)
359*9f20bfa6SDavid van Moolenbroek {
360*9f20bfa6SDavid van Moolenbroek struct fd_list *fd;
361*9f20bfa6SDavid van Moolenbroek struct iovec iov[2];
362*9f20bfa6SDavid van Moolenbroek struct fd_data *data;
363*9f20bfa6SDavid van Moolenbroek
364*9f20bfa6SDavid van Moolenbroek fd = arg;
365*9f20bfa6SDavid van Moolenbroek data = TAILQ_FIRST(&fd->queue);
366*9f20bfa6SDavid van Moolenbroek iov[0].iov_base = &data->data_len;
367*9f20bfa6SDavid van Moolenbroek iov[0].iov_len = sizeof(size_t);
368*9f20bfa6SDavid van Moolenbroek iov[1].iov_base = data->data;
369*9f20bfa6SDavid van Moolenbroek iov[1].iov_len = data->data_len;
370*9f20bfa6SDavid van Moolenbroek if (writev(fd->fd, iov, 2) == -1) {
371*9f20bfa6SDavid van Moolenbroek logger(fd->ctx, LOG_ERR,
372*9f20bfa6SDavid van Moolenbroek "%s: writev fd %d: %m", __func__, fd->fd);
373*9f20bfa6SDavid van Moolenbroek if (errno != EINTR && errno != EAGAIN)
374*9f20bfa6SDavid van Moolenbroek control_delete(fd);
375*9f20bfa6SDavid van Moolenbroek return;
376*9f20bfa6SDavid van Moolenbroek }
377*9f20bfa6SDavid van Moolenbroek
378*9f20bfa6SDavid van Moolenbroek TAILQ_REMOVE(&fd->queue, data, next);
379*9f20bfa6SDavid van Moolenbroek if (data->freeit)
380*9f20bfa6SDavid van Moolenbroek control_queue_purge(fd->ctx, data->data);
381*9f20bfa6SDavid van Moolenbroek data->data = NULL; /* safety */
382*9f20bfa6SDavid van Moolenbroek data->data_len = 0;
383*9f20bfa6SDavid van Moolenbroek TAILQ_INSERT_TAIL(&fd->free_queue, data, next);
384*9f20bfa6SDavid van Moolenbroek
385*9f20bfa6SDavid van Moolenbroek if (TAILQ_FIRST(&fd->queue) == NULL)
386*9f20bfa6SDavid van Moolenbroek eloop_event_remove_writecb(fd->ctx->eloop, fd->fd);
387*9f20bfa6SDavid van Moolenbroek }
388*9f20bfa6SDavid van Moolenbroek
389*9f20bfa6SDavid van Moolenbroek int
control_queue(struct fd_list * fd,char * data,size_t data_len,uint8_t fit)390*9f20bfa6SDavid van Moolenbroek control_queue(struct fd_list *fd, char *data, size_t data_len, uint8_t fit)
391*9f20bfa6SDavid van Moolenbroek {
392*9f20bfa6SDavid van Moolenbroek struct fd_data *d;
393*9f20bfa6SDavid van Moolenbroek size_t n;
394*9f20bfa6SDavid van Moolenbroek
395*9f20bfa6SDavid van Moolenbroek d = TAILQ_FIRST(&fd->free_queue);
396*9f20bfa6SDavid van Moolenbroek if (d) {
397*9f20bfa6SDavid van Moolenbroek TAILQ_REMOVE(&fd->free_queue, d, next);
398*9f20bfa6SDavid van Moolenbroek } else {
399*9f20bfa6SDavid van Moolenbroek n = 0;
400*9f20bfa6SDavid van Moolenbroek TAILQ_FOREACH(d, &fd->queue, next) {
401*9f20bfa6SDavid van Moolenbroek if (++n == CONTROL_QUEUE_MAX) {
402*9f20bfa6SDavid van Moolenbroek errno = ENOBUFS;
403*9f20bfa6SDavid van Moolenbroek return -1;
404*9f20bfa6SDavid van Moolenbroek }
405*9f20bfa6SDavid van Moolenbroek }
406*9f20bfa6SDavid van Moolenbroek d = malloc(sizeof(*d));
407*9f20bfa6SDavid van Moolenbroek if (d == NULL)
408*9f20bfa6SDavid van Moolenbroek return -1;
409*9f20bfa6SDavid van Moolenbroek }
410*9f20bfa6SDavid van Moolenbroek d->data = data;
411*9f20bfa6SDavid van Moolenbroek d->data_len = data_len;
412*9f20bfa6SDavid van Moolenbroek d->freeit = fit;
413*9f20bfa6SDavid van Moolenbroek TAILQ_INSERT_TAIL(&fd->queue, d, next);
414*9f20bfa6SDavid van Moolenbroek eloop_event_add(fd->ctx->eloop, fd->fd,
415*9f20bfa6SDavid van Moolenbroek NULL, NULL, control_writeone, fd);
416*9f20bfa6SDavid van Moolenbroek return 0;
417*9f20bfa6SDavid van Moolenbroek }
418*9f20bfa6SDavid van Moolenbroek
419*9f20bfa6SDavid van Moolenbroek void
control_close(struct dhcpcd_ctx * ctx)420*9f20bfa6SDavid van Moolenbroek control_close(struct dhcpcd_ctx *ctx)
421*9f20bfa6SDavid van Moolenbroek {
422*9f20bfa6SDavid van Moolenbroek
423*9f20bfa6SDavid van Moolenbroek if (ctx->control_fd != -1) {
424*9f20bfa6SDavid van Moolenbroek close(ctx->control_fd);
425*9f20bfa6SDavid van Moolenbroek ctx->control_fd = -1;
426*9f20bfa6SDavid van Moolenbroek }
427*9f20bfa6SDavid van Moolenbroek }
428