xref: /minix3/external/bsd/dhcpcd/dist/control.c (revision 9f20bfa6c4c442e2e798d91b11c2a5f8d6833a41)
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