1/* 2 * libudev - interface to udev device information 3 * 4 * Copyright (C) 2008 Kay Sievers <kay@vrfy.org> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 */ 11 12#include <errno.h> 13#include <fcntl.h> 14#include <stdio.h> 15#include <stdlib.h> 16#include <stddef.h> 17#include <string.h> 18#include <unistd.h> 19#include <sys/types.h> 20#include <poll.h> 21#include <sys/socket.h> 22#include <sys/un.h> 23 24#include "socket-util.h" 25#include "udev.h" 26 27/* wire protocol magic must match */ 28#define UDEV_CTRL_MAGIC 0xdead1dea 29 30enum udev_ctrl_msg_type { 31 UDEV_CTRL_UNKNOWN, 32 UDEV_CTRL_SET_LOG_LEVEL, 33 UDEV_CTRL_STOP_EXEC_QUEUE, 34 UDEV_CTRL_START_EXEC_QUEUE, 35 UDEV_CTRL_RELOAD, 36 UDEV_CTRL_SET_ENV, 37 UDEV_CTRL_SET_CHILDREN_MAX, 38 UDEV_CTRL_PING, 39 UDEV_CTRL_EXIT, 40}; 41 42struct udev_ctrl_msg_wire { 43 char version[16]; 44 unsigned int magic; 45 enum udev_ctrl_msg_type type; 46 union { 47 int intval; 48 char buf[256]; 49 }; 50}; 51 52struct udev_ctrl_msg { 53 int refcount; 54 struct udev_ctrl_connection *conn; 55 struct udev_ctrl_msg_wire ctrl_msg_wire; 56}; 57 58struct udev_ctrl { 59 int refcount; 60 struct udev *udev; 61 int sock; 62 union sockaddr_union saddr; 63 socklen_t addrlen; 64 bool bound; 65 bool cleanup_socket; 66 bool connected; 67}; 68 69struct udev_ctrl_connection { 70 int refcount; 71 struct udev_ctrl *uctrl; 72 int sock; 73}; 74 75struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) { 76 struct udev_ctrl *uctrl; 77 const int on = 1; 78 int r; 79 80 uctrl = new0(struct udev_ctrl, 1); 81 if (uctrl == NULL) 82 return NULL; 83 uctrl->refcount = 1; 84 uctrl->udev = udev; 85 86 if (fd < 0) { 87 uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0); 88 if (uctrl->sock < 0) { 89 log_error_errno(errno, "error getting socket: %m"); 90 udev_ctrl_unref(uctrl); 91 return NULL; 92 } 93 } else { 94 uctrl->bound = true; 95 uctrl->sock = fd; 96 } 97 r = setsockopt(uctrl->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); 98 if (r < 0) 99 log_warning_errno(errno, "could not set SO_PASSCRED: %m"); 100 101 uctrl->saddr.un.sun_family = AF_LOCAL; 102 strscpy(uctrl->saddr.un.sun_path, sizeof(uctrl->saddr.un.sun_path), UDEV_ROOT_RUN "/udev/control"); 103 uctrl->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(uctrl->saddr.un.sun_path); 104 return uctrl; 105} 106 107struct udev_ctrl *udev_ctrl_new(struct udev *udev) { 108 return udev_ctrl_new_from_fd(udev, -1); 109} 110 111int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) { 112 int err; 113 114 if (!uctrl->bound) { 115 err = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen); 116 if (err < 0 && errno == EADDRINUSE) { 117 unlink(uctrl->saddr.un.sun_path); 118 err = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen); 119 } 120 121 if (err < 0) { 122 err = -errno; 123 log_error_errno(errno, "bind failed: %m"); 124 return err; 125 } 126 127 err = listen(uctrl->sock, 0); 128 if (err < 0) { 129 err = -errno; 130 log_error_errno(errno, "listen failed: %m"); 131 return err; 132 } 133 134 uctrl->bound = true; 135 uctrl->cleanup_socket = true; 136 } 137 return 0; 138} 139 140struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl) { 141 return uctrl->udev; 142} 143 144static struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl) { 145 if (uctrl) 146 uctrl->refcount++; 147 148 return uctrl; 149} 150 151struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl) { 152 if (uctrl && -- uctrl->refcount == 0) { 153 if (uctrl->sock >= 0) 154 close(uctrl->sock); 155 free(uctrl); 156 } 157 158 return NULL; 159} 160 161int udev_ctrl_cleanup(struct udev_ctrl *uctrl) { 162 if (uctrl == NULL) 163 return 0; 164 if (uctrl->cleanup_socket) 165 unlink(uctrl->saddr.un.sun_path); 166 return 0; 167} 168 169int udev_ctrl_get_fd(struct udev_ctrl *uctrl) { 170 if (uctrl == NULL) 171 return -EINVAL; 172 return uctrl->sock; 173} 174 175static inline int accept4_fallback(int sockfd) { 176 int fd; 177 178 /* This is racey, but what can we do without accept4? */ 179 if ((fd = accept(sockfd, NULL, NULL)) >= 0) { 180 fcntl(fd, F_SETFL, O_NONBLOCK); 181 fcntl(fd, F_SETFD, FD_CLOEXEC); 182 } 183 184 return fd; 185} 186 187struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl) { 188 struct udev_ctrl_connection *conn; 189 struct ucred ucred = {}; 190 const int on = 1; 191 int r; 192 193 conn = new(struct udev_ctrl_connection, 1); 194 if (conn == NULL) 195 return NULL; 196 conn->refcount = 1; 197 conn->uctrl = uctrl; 198 199#if HAVE_DECL_ACCEPT4 200 conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK); 201 202 /* Fallback path when accept4() is unavailable */ 203 if ( conn->sock < 0 && (errno == ENOSYS || errno == EOPNOTSUPP) ) 204 conn->sock = accept4_fallback(uctrl->sock); 205#else 206 conn->sock = accept4_fallback(uctrl->sock); 207#endif 208 209 if (conn->sock < 0) { 210 if (errno != EINTR) 211 log_error_errno(errno, "unable to receive ctrl connection: %m"); 212 goto err; 213 } 214 215 /* check peer credential of connection */ 216 r = getpeercred(conn->sock, &ucred); 217 if (r < 0) { 218 log_error_errno(r, "unable to receive credentials of ctrl connection: %m"); 219 goto err; 220 } 221 if (ucred.uid > 0) { 222 log_error("sender uid="UID_FMT", message ignored", ucred.uid); 223 goto err; 224 } 225 226 /* enable receiving of the sender credentials in the messages */ 227 r = setsockopt(conn->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); 228 if (r < 0) 229 log_warning_errno(errno, "could not set SO_PASSCRED: %m"); 230 231 udev_ctrl_ref(uctrl); 232 return conn; 233err: 234 if (conn->sock >= 0) 235 close(conn->sock); 236 free(conn); 237 return NULL; 238} 239 240struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connection *conn) { 241 if (conn == NULL) 242 return NULL; 243 conn->refcount++; 244 return conn; 245} 246 247struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn) { 248 if (conn && -- conn->refcount == 0) { 249 if (conn->sock >= 0) 250 close(conn->sock); 251 252 udev_ctrl_unref(conn->uctrl); 253 254 free(conn); 255 } 256 257 return NULL; 258} 259 260static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, int timeout) { 261 struct udev_ctrl_msg_wire ctrl_msg_wire; 262 int err = 0; 263 264 memzero(&ctrl_msg_wire, sizeof(struct udev_ctrl_msg_wire)); 265 strcpy(ctrl_msg_wire.version, "udev-" VERSION); 266 ctrl_msg_wire.magic = UDEV_CTRL_MAGIC; 267 ctrl_msg_wire.type = type; 268 269 if (buf != NULL) 270 strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf); 271 else 272 ctrl_msg_wire.intval = intval; 273 274 if (!uctrl->connected) { 275 if (connect(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen) < 0) { 276 err = -errno; 277 goto out; 278 } 279 uctrl->connected = true; 280 } 281 if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0) { 282 err = -errno; 283 goto out; 284 } 285 286 /* wait for peer message handling or disconnect */ 287 for (;;) { 288 struct pollfd pfd[1]; 289 int r; 290 291 pfd[0].fd = uctrl->sock; 292 pfd[0].events = POLLIN; 293 r = poll(pfd, 1, timeout * MSEC_PER_SEC); 294 if (r < 0) { 295 if (errno == EINTR) 296 continue; 297 err = -errno; 298 break; 299 } 300 301 if (r > 0 && pfd[0].revents & POLLERR) { 302 err = -EIO; 303 break; 304 } 305 306 if (r == 0) 307 err = -ETIMEDOUT; 308 break; 309 } 310out: 311 return err; 312} 313 314int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout) { 315 return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL, timeout); 316} 317 318int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout) { 319 return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout); 320} 321 322int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout) { 323 return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout); 324} 325 326int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout) { 327 return ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL, timeout); 328} 329 330int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout) { 331 return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout); 332} 333 334int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout) { 335 return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout); 336} 337 338int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout) { 339 return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout); 340} 341 342int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout) { 343 return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout); 344} 345 346struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn) { 347 struct udev_ctrl_msg *uctrl_msg; 348 ssize_t size; 349 struct cmsghdr *cmsg; 350 struct iovec iov; 351 char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; 352 struct msghdr smsg = { 353 .msg_iov = &iov, 354 .msg_iovlen = 1, 355 .msg_control = cred_msg, 356 .msg_controllen = sizeof(cred_msg), 357 }; 358 struct ucred *cred; 359 360 uctrl_msg = new0(struct udev_ctrl_msg, 1); 361 if (uctrl_msg == NULL) 362 return NULL; 363 uctrl_msg->refcount = 1; 364 uctrl_msg->conn = conn; 365 udev_ctrl_connection_ref(conn); 366 367 /* wait for the incoming message */ 368 for (;;) { 369 struct pollfd pfd[1]; 370 int r; 371 372 pfd[0].fd = conn->sock; 373 pfd[0].events = POLLIN; 374 375 r = poll(pfd, 1, 10000); 376 if (r < 0) { 377 if (errno == EINTR) 378 continue; 379 goto err; 380 } else if (r == 0) { 381 log_error("timeout waiting for ctrl message"); 382 goto err; 383 } else { 384 if (!(pfd[0].revents & POLLIN)) { 385 log_error_errno(errno, "ctrl connection error: %m"); 386 goto err; 387 } 388 } 389 390 break; 391 } 392 393 iov.iov_base = &uctrl_msg->ctrl_msg_wire; 394 iov.iov_len = sizeof(struct udev_ctrl_msg_wire); 395 396 size = recvmsg(conn->sock, &smsg, 0); 397 if (size < 0) { 398 log_error_errno(errno, "unable to receive ctrl message: %m"); 399 goto err; 400 } 401 402 cmsg_close_all(&smsg); 403 404 cmsg = CMSG_FIRSTHDR(&smsg); 405 cred = (struct ucred *) CMSG_DATA(cmsg); 406 407 if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { 408 log_error("no sender credentials received, message ignored"); 409 goto err; 410 } 411 412 if (cred->uid != 0) { 413 log_error("sender uid="UID_FMT", message ignored", cred->uid); 414 goto err; 415 } 416 417 if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) { 418 log_error("message magic 0x%08x doesn't match, ignore it", uctrl_msg->ctrl_msg_wire.magic); 419 goto err; 420 } 421 422 return uctrl_msg; 423err: 424 udev_ctrl_msg_unref(uctrl_msg); 425 return NULL; 426} 427 428struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg) { 429 if (ctrl_msg && -- ctrl_msg->refcount == 0) { 430 udev_ctrl_connection_unref(ctrl_msg->conn); 431 free(ctrl_msg); 432 } 433 434 return NULL; 435} 436 437int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg) { 438 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_LOG_LEVEL) 439 return ctrl_msg->ctrl_msg_wire.intval; 440 return -1; 441} 442 443int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg) { 444 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_STOP_EXEC_QUEUE) 445 return 1; 446 return -1; 447} 448 449int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg) { 450 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_START_EXEC_QUEUE) 451 return 1; 452 return -1; 453} 454 455int udev_ctrl_get_reload(struct udev_ctrl_msg *ctrl_msg) { 456 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_RELOAD) 457 return 1; 458 return -1; 459} 460 461const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg) { 462 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_ENV) 463 return ctrl_msg->ctrl_msg_wire.buf; 464 return NULL; 465} 466 467int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg) { 468 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_CHILDREN_MAX) 469 return ctrl_msg->ctrl_msg_wire.intval; 470 return -1; 471} 472 473int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg) { 474 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_PING) 475 return 1; 476 return -1; 477} 478 479int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg) { 480 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_EXIT) 481 return 1; 482 return -1; 483} 484