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