xref: /third_party/eudev/src/udev/udev-ctrl.c (revision 99ca880a)
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