1 /* SPDX-License-Identifier: BSD-2-Clause */
3 * dhcpcd - DHCP client daemon
4 * Copyright (c) 2006-2020 Roy Marples <roy@marples.name>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/socket.h>
53 (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
57 control_queue_free(struct fd_list
*fd
)
61 while ((fdp
= TAILQ_FIRST(&fd
->queue
))) {
62 TAILQ_REMOVE(&fd
->queue
, fdp
, next
);
63 if (fdp
->data_size
!= 0)
69 while ((fdp
= TAILQ_FIRST(&fd
->free_queue
))) {
70 TAILQ_REMOVE(&fd
->free_queue
, fdp
, next
);
71 if (fdp
->data_size
!= 0)
79 control_free(struct fd_list
*fd
)
83 if (fd
->ctx
->ps_control_client
== fd
)
84 fd
->ctx
->ps_control_client
= NULL
;
87 eloop_event_remove_writecb(fd
->ctx
->eloop
, fd
->fd
);
88 TAILQ_REMOVE(&fd
->ctx
->control_fds
, fd
, next
);
89 control_queue_free(fd
);
94 control_delete(struct fd_list
*fd
)
98 if (IN_PRIVSEP_SE(fd
->ctx
))
102 eloop_event_delete(fd
->ctx
->eloop
, fd
->fd
);
108 control_handle_data(void *arg
)
110 struct fd_list
*fd
= arg
;
114 bytes
= read(fd
->fd
, buffer
, sizeof(buffer
) - 1);
116 if (bytes
== -1 || bytes
== 0) {
117 /* Control was closed or there was an error.
118 * Remove it from our list. */
124 if (IN_PRIVSEP(fd
->ctx
)) {
127 fd
->flags
|= FD_SENDLEN
;
128 err
= ps_ctl_handleargs(fd
, buffer
, (size_t)bytes
);
129 fd
->flags
&= ~FD_SENDLEN
;
135 ps_ctl_sendargs(fd
, buffer
, (size_t)bytes
) == -1) {
143 control_recvdata(fd
, buffer
, (size_t)bytes
);
147 control_recvdata(struct fd_list
*fd
, char *data
, size_t len
)
150 char *argvp
[255], **ap
;
153 /* Each command is \n terminated
154 * Each argument is NULL separated */
164 e
= memchr(p
, '\0', len
);
167 logerrx("%s: no terminator", __func__
);
170 if ((size_t)argc
>= sizeof(argvp
) / sizeof(argvp
[0])) {
172 logerrx("%s: no arg buffer", __func__
);
178 len
-= (size_t)(e
- p
);
181 if (*(--e
) == '\n') {
187 logerrx("%s: no args", __func__
);
191 if (dhcpcd_handleargs(fd
->ctx
, fd
, argc
, argvp
) == -1) {
193 if (errno
!= EINTR
&& errno
!= EAGAIN
) {
202 control_new(struct dhcpcd_ctx
*ctx
, int fd
, unsigned int flags
)
206 l
= malloc(sizeof(*l
));
213 TAILQ_INIT(&l
->queue
);
215 TAILQ_INIT(&l
->free_queue
);
217 TAILQ_INSERT_TAIL(&ctx
->control_fds
, l
, next
);
222 control_handle1(struct dhcpcd_ctx
*ctx
, int lfd
, unsigned int fd_flags
)
224 struct sockaddr_un run
;
230 if ((fd
= accept(lfd
, (struct sockaddr
*)&run
, &len
)) == -1)
232 if ((flags
= fcntl(fd
, F_GETFD
, 0)) == -1 ||
233 fcntl(fd
, F_SETFD
, flags
| FD_CLOEXEC
) == -1)
235 if ((flags
= fcntl(fd
, F_GETFL
, 0)) == -1 ||
236 fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
) == -1)
240 if (IN_PRIVSEP(ctx
) && !IN_PRIVSEP_SE(ctx
))
244 fd_flags
|= FD_SENDLEN
;
246 l
= control_new(ctx
, fd
, fd_flags
);
250 if (eloop_event_add(ctx
->eloop
, l
->fd
, control_handle_data
, l
) == -1)
261 control_handle(void *arg
)
263 struct dhcpcd_ctx
*ctx
= arg
;
265 control_handle1(ctx
, ctx
->control_fd
, 0);
269 control_handle_unpriv(void *arg
)
271 struct dhcpcd_ctx
*ctx
= arg
;
273 control_handle1(ctx
, ctx
->control_unpriv_fd
, FD_UNPRIV
);
277 make_path(char *path
, size_t len
, const char *ifname
, sa_family_t family
,
295 sunpriv
= ifname
? ".unpriv" : "unpriv.";
298 return snprintf(path
, len
, CONTROLSOCKET
,
299 ifname
? ifname
: "", ifname
? per
: "",
300 sunpriv
, ifname
? "." : "");
304 make_sock(struct sockaddr_un
*sa
, const char *ifname
, sa_family_t family
,
309 if ((fd
= xsocket(AF_UNIX
, SOCK_STREAM
| SOCK_CXNB
, 0)) == -1)
311 memset(sa
, 0, sizeof(*sa
));
312 sa
->sun_family
= AF_UNIX
;
313 make_path(sa
->sun_path
, sizeof(sa
->sun_path
), ifname
, family
, unpriv
);
317 #define S_PRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
318 #define S_UNPRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
321 control_start1(struct dhcpcd_ctx
*ctx
, const char *ifname
, sa_family_t family
,
324 struct sockaddr_un sa
;
328 fd
= make_sock(&sa
, ifname
, family
, (fmode
& S_UNPRIV
) == S_UNPRIV
);
332 len
= (socklen_t
)SUN_LEN(&sa
);
334 if (bind(fd
, (struct sockaddr
*)&sa
, len
) == -1 ||
335 chmod(sa
.sun_path
, fmode
) == -1 ||
336 (ctx
->control_group
&&
337 chown(sa
.sun_path
, geteuid(), ctx
->control_group
) == -1) ||
338 listen(fd
, sizeof(ctx
->control_fds
)) == -1)
345 #ifdef PRIVSEP_RIGHTS
346 if (IN_PRIVSEP(ctx
) && ps_rights_limit_fd_fctnl(fd
) == -1) {
353 if ((fmode
& S_PRIV
) == S_PRIV
)
354 strlcpy(ctx
->control_sock
, sa
.sun_path
,
355 sizeof(ctx
->control_sock
));
357 strlcpy(ctx
->control_sock_unpriv
, sa
.sun_path
,
358 sizeof(ctx
->control_sock_unpriv
));
363 control_start(struct dhcpcd_ctx
*ctx
, const char *ifname
, sa_family_t family
)
368 if (IN_PRIVSEP_SE(ctx
)) {
369 make_path(ctx
->control_sock
, sizeof(ctx
->control_sock
),
370 ifname
, family
, false);
371 make_path(ctx
->control_sock_unpriv
, sizeof(ctx
->control_sock
),
372 ifname
, family
, true);
377 if ((fd
= control_start1(ctx
, ifname
, family
, S_PRIV
)) == -1)
380 ctx
->control_fd
= fd
;
381 eloop_event_add(ctx
->eloop
, fd
, control_handle
, ctx
);
383 if ((fd
= control_start1(ctx
, ifname
, family
, S_UNPRIV
)) != -1) {
384 ctx
->control_unpriv_fd
= fd
;
385 eloop_event_add(ctx
->eloop
, fd
, control_handle_unpriv
, ctx
);
387 return ctx
->control_fd
;
391 control_unlink(struct dhcpcd_ctx
*ctx
, const char *file
)
398 retval
= (int)ps_root_unlink(ctx
, file
);
403 retval
= unlink(file
);
405 return retval
== -1 && errno
!= ENOENT
? -1 : 0;
409 control_stop(struct dhcpcd_ctx
*ctx
)
414 while ((l
= TAILQ_FIRST(&ctx
->control_fds
)) != NULL
) {
419 if (IN_PRIVSEP_SE(ctx
)) {
420 if (ps_root_unlink(ctx
, ctx
->control_sock
) == -1)
422 if (ps_root_unlink(ctx
, ctx
->control_sock_unpriv
) == -1)
425 } else if (ctx
->options
& DHCPCD_FORKED
)
429 if (ctx
->control_fd
!= -1) {
430 eloop_event_delete(ctx
->eloop
, ctx
->control_fd
);
431 close(ctx
->control_fd
);
432 ctx
->control_fd
= -1;
433 if (control_unlink(ctx
, ctx
->control_sock
) == -1)
437 if (ctx
->control_unpriv_fd
!= -1) {
438 eloop_event_delete(ctx
->eloop
, ctx
->control_unpriv_fd
);
439 close(ctx
->control_unpriv_fd
);
440 ctx
->control_unpriv_fd
= -1;
441 if (control_unlink(ctx
, ctx
->control_sock_unpriv
) == -1)
449 control_open(const char *ifname
, sa_family_t family
, bool unpriv
)
451 struct sockaddr_un sa
;
454 if ((fd
= make_sock(&sa
, ifname
, family
, unpriv
)) != -1) {
457 len
= (socklen_t
)SUN_LEN(&sa
);
458 if (connect(fd
, (struct sockaddr
*)&sa
, len
) == -1) {
467 control_send(struct dhcpcd_ctx
*ctx
, int argc
, char * const *argv
)
478 for (i
= 0; i
< argc
; i
++) {
479 l
= strlen(argv
[i
]) + 1;
480 if (len
+ l
> sizeof(buffer
)) {
484 memcpy(buffer
+ len
, argv
[i
], l
);
487 return write(ctx
->control_fd
, buffer
, len
);
491 control_writeone(void *arg
)
496 struct fd_data
*data
;
499 data
= TAILQ_FIRST(&fd
->queue
);
501 if (data
->data_flags
& FD_SENDLEN
) {
502 iov
[0].iov_base
= &data
->data_len
;
503 iov
[0].iov_len
= sizeof(size_t);
504 iov
[1].iov_base
= data
->data
;
505 iov
[1].iov_len
= data
->data_len
;
508 iov
[0].iov_base
= data
->data
;
509 iov
[0].iov_len
= data
->data_len
;
513 if (writev(fd
->fd
, iov
, iov_len
) == -1) {
514 logerr("%s: write", __func__
);
519 TAILQ_REMOVE(&fd
->queue
, data
, next
);
521 TAILQ_INSERT_TAIL(&fd
->free_queue
, data
, next
);
523 if (data
->data_size
!= 0)
528 if (TAILQ_FIRST(&fd
->queue
) != NULL
)
531 eloop_event_remove_writecb(fd
->ctx
->eloop
, fd
->fd
);
533 if (IN_PRIVSEP_SE(fd
->ctx
) && !(fd
->flags
& FD_LISTEN
)) {
534 if (ps_ctl_sendeof(fd
) == -1)
542 control_queue(struct fd_list
*fd
, void *data
, size_t data_len
)
555 TAILQ_FOREACH(df
, &fd
->free_queue
, next
) {
556 if (d
== NULL
|| d
->data_size
< df
->data_size
) {
558 if (d
->data_size
<= data_len
)
563 TAILQ_REMOVE(&fd
->free_queue
, d
, next
);
567 d
= calloc(1, sizeof(*d
));
572 if (d
->data_size
== 0)
574 if (d
->data_size
< data_len
) {
575 void *nbuf
= realloc(d
->data
, data_len
);
582 d
->data_size
= data_len
;
584 memcpy(d
->data
, data
, data_len
);
585 d
->data_len
= data_len
;
586 d
->data_flags
= fd
->flags
& FD_SENDLEN
;
588 TAILQ_INSERT_TAIL(&fd
->queue
, d
, next
);
589 eloop_event_add_w(fd
->ctx
->eloop
, fd
->fd
, control_writeone
, fd
);