1 /* 2 * dhcpcd - DHCP client daemon 3 * Copyright (c) 2006-2018 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 #include "if.h" 47 #include "logerr.h" 48 49 #ifndef SUN_LEN 50 #define SUN_LEN(su) \ 51 (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) 52 #endif 53 54 static void 55 control_queue_purge(struct dhcpcd_ctx *ctx, char *data) 56 { 57 int found; 58 struct fd_list *fp; 59 struct fd_data *fpd; 60 61 /* If no other fd queue has the same data, free it */ 62 found = 0; 63 TAILQ_FOREACH(fp, &ctx->control_fds, next) { 64 TAILQ_FOREACH(fpd, &fp->queue, next) { 65 if (fpd->data == data) { 66 found = 1; 67 break; 68 } 69 } 70 } 71 if (!found) 72 free(data); 73 } 74 75 static void 76 control_queue_free(struct fd_list *fd) 77 { 78 struct fd_data *fdp; 79 80 while ((fdp = TAILQ_FIRST(&fd->queue))) { 81 TAILQ_REMOVE(&fd->queue, fdp, next); 82 if (fdp->freeit) 83 control_queue_purge(fd->ctx, fdp->data); 84 free(fdp); 85 } 86 while ((fdp = TAILQ_FIRST(&fd->free_queue))) { 87 TAILQ_REMOVE(&fd->free_queue, fdp, next); 88 free(fdp); 89 } 90 } 91 92 static void 93 control_delete(struct fd_list *fd) 94 { 95 96 TAILQ_REMOVE(&fd->ctx->control_fds, fd, next); 97 eloop_event_delete(fd->ctx->eloop, fd->fd); 98 close(fd->fd); 99 control_queue_free(fd); 100 free(fd); 101 } 102 103 static void 104 control_handle_data(void *arg) 105 { 106 struct fd_list *fd = arg; 107 char buffer[1024], *e, *p, *argvp[255], **ap, *a; 108 ssize_t bytes; 109 size_t len; 110 int argc; 111 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. */ 116 control_delete(fd); 117 return; 118 } 119 buffer[bytes] = '\0'; 120 p = buffer; 121 e = buffer + bytes; 122 123 /* Each command is \n terminated 124 * Each argument is NULL separated */ 125 while (p < e) { 126 argc = 0; 127 ap = argvp; 128 while (p < e) { 129 argc++; 130 if ((size_t)argc >= sizeof(argvp) / sizeof(argvp[0])) { 131 errno = ENOBUFS; 132 return; 133 } 134 a = *ap++ = p; 135 len = strlen(p); 136 p += len + 1; 137 if (len && a[len - 1] == '\n') { 138 a[len - 1] = '\0'; 139 break; 140 } 141 } 142 *ap = NULL; 143 if (dhcpcd_handleargs(fd->ctx, fd, argc, argvp) == -1) { 144 logerr(__func__); 145 if (errno != EINTR && errno != EAGAIN) { 146 control_delete(fd); 147 return; 148 } 149 } 150 } 151 } 152 153 static void 154 control_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags) 155 { 156 struct sockaddr_un run; 157 socklen_t len; 158 struct fd_list *l; 159 int fd, flags; 160 161 len = sizeof(run); 162 if ((fd = accept(lfd, (struct sockaddr *)&run, &len)) == -1) 163 return; 164 if ((flags = fcntl(fd, F_GETFD, 0)) == -1 || 165 fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) 166 { 167 close(fd); 168 return; 169 } 170 if ((flags = fcntl(fd, F_GETFL, 0)) == -1 || 171 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) 172 { 173 close(fd); 174 return; 175 } 176 l = malloc(sizeof(*l)); 177 if (l) { 178 l->ctx = ctx; 179 l->fd = fd; 180 l->flags = fd_flags; 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); 185 } else 186 close(fd); 187 } 188 189 static void 190 control_handle(void *arg) 191 { 192 struct dhcpcd_ctx *ctx = arg; 193 194 control_handle1(ctx, ctx->control_fd, 0); 195 } 196 197 static void 198 control_handle_unpriv(void *arg) 199 { 200 struct dhcpcd_ctx *ctx = arg; 201 202 control_handle1(ctx, ctx->control_unpriv_fd, FD_UNPRIV); 203 } 204 205 static int 206 make_sock(struct sockaddr_un *sa, const char *ifname, int unpriv) 207 { 208 int fd; 209 210 #define SOCK_FLAGS SOCK_CLOEXEC | SOCK_NONBLOCK 211 if ((fd = xsocket(AF_UNIX, SOCK_STREAM | SOCK_FLAGS, 0)) == -1) 212 return -1; 213 #undef SOCK_FLAGS 214 memset(sa, 0, sizeof(*sa)); 215 sa->sun_family = AF_UNIX; 216 if (unpriv) 217 strlcpy(sa->sun_path, UNPRIVSOCKET, sizeof(sa->sun_path)); 218 else { 219 snprintf(sa->sun_path, sizeof(sa->sun_path), CONTROLSOCKET, 220 ifname ? "-" : "", ifname ? ifname : ""); 221 } 222 return fd; 223 } 224 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) 227 228 static int 229 control_start1(struct dhcpcd_ctx *ctx, const char *ifname, mode_t fmode) 230 { 231 struct sockaddr_un sa; 232 int fd; 233 socklen_t len; 234 235 if ((fd = make_sock(&sa, ifname, (fmode & S_UNPRIV) == S_UNPRIV)) == -1) 236 return -1; 237 len = (socklen_t)SUN_LEN(&sa); 238 unlink(sa.sun_path); 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) 244 { 245 close(fd); 246 unlink(sa.sun_path); 247 return -1; 248 } 249 250 if ((fmode & S_UNPRIV) != S_UNPRIV) 251 strlcpy(ctx->control_sock, sa.sun_path, 252 sizeof(ctx->control_sock)); 253 return fd; 254 } 255 256 int 257 control_start(struct dhcpcd_ctx *ctx, const char *ifname) 258 { 259 int fd; 260 261 if ((fd = control_start1(ctx, ifname, S_PRIV)) == -1) 262 return -1; 263 264 ctx->control_fd = fd; 265 eloop_event_add(ctx->eloop, fd, control_handle, ctx); 266 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); 272 } 273 return ctx->control_fd; 274 } 275 276 int 277 control_stop(struct dhcpcd_ctx *ctx) 278 { 279 int retval = 0; 280 struct fd_list *l; 281 282 if (ctx->options & DHCPCD_FORKED) 283 goto freeit; 284 285 if (ctx->control_fd == -1) 286 return 0; 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) 291 retval = -1; 292 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) 298 retval = -1; 299 } 300 301 freeit: 302 while ((l = TAILQ_FIRST(&ctx->control_fds))) { 303 TAILQ_REMOVE(&ctx->control_fds, l, next); 304 eloop_event_delete(ctx->eloop, l->fd); 305 close(l->fd); 306 control_queue_free(l); 307 free(l); 308 } 309 310 return retval; 311 } 312 313 int 314 control_open(const char *ifname) 315 { 316 struct sockaddr_un sa; 317 int fd; 318 319 if ((fd = make_sock(&sa, ifname, 0)) != -1) { 320 socklen_t len; 321 322 len = (socklen_t)SUN_LEN(&sa); 323 if (connect(fd, (struct sockaddr *)&sa, len) == -1) { 324 close(fd); 325 fd = -1; 326 } 327 } 328 return fd; 329 } 330 331 ssize_t 332 control_send(struct dhcpcd_ctx *ctx, int argc, char * const *argv) 333 { 334 char buffer[1024]; 335 int i; 336 size_t len, l; 337 338 if (argc > 255) { 339 errno = ENOBUFS; 340 return -1; 341 } 342 len = 0; 343 for (i = 0; i < argc; i++) { 344 l = strlen(argv[i]) + 1; 345 if (len + l > sizeof(buffer)) { 346 errno = ENOBUFS; 347 return -1; 348 } 349 memcpy(buffer + len, argv[i], l); 350 len += l; 351 } 352 return write(ctx->control_fd, buffer, len); 353 } 354 355 static void 356 control_writeone(void *arg) 357 { 358 struct fd_list *fd; 359 struct iovec iov[2]; 360 struct fd_data *data; 361 362 fd = arg; 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) { 369 logerr(__func__); 370 if (errno != EINTR && errno != EAGAIN) 371 control_delete(fd); 372 return; 373 } 374 375 TAILQ_REMOVE(&fd->queue, data, next); 376 if (data->freeit) 377 control_queue_purge(fd->ctx, data->data); 378 data->data = NULL; /* safety */ 379 data->data_len = 0; 380 TAILQ_INSERT_TAIL(&fd->free_queue, data, next); 381 382 if (TAILQ_FIRST(&fd->queue) == NULL) 383 eloop_event_remove_writecb(fd->ctx->eloop, fd->fd); 384 } 385 386 int 387 control_queue(struct fd_list *fd, char *data, size_t data_len, uint8_t fit) 388 { 389 struct fd_data *d; 390 size_t n; 391 392 d = TAILQ_FIRST(&fd->free_queue); 393 if (d) { 394 TAILQ_REMOVE(&fd->free_queue, d, next); 395 } else { 396 n = 0; 397 TAILQ_FOREACH(d, &fd->queue, next) { 398 if (++n == CONTROL_QUEUE_MAX) { 399 errno = ENOBUFS; 400 return -1; 401 } 402 } 403 d = malloc(sizeof(*d)); 404 if (d == NULL) 405 return -1; 406 } 407 d->data = data; 408 d->data_len = data_len; 409 d->freeit = fit; 410 TAILQ_INSERT_TAIL(&fd->queue, d, next); 411 eloop_event_add_w(fd->ctx->eloop, fd->fd, control_writeone, fd); 412 return 0; 413 } 414 415 void 416 control_close(struct dhcpcd_ctx *ctx) 417 { 418 419 if (ctx->control_fd != -1) { 420 close(ctx->control_fd); 421 ctx->control_fd = -1; 422 } 423 } 424