]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-daemon/sd-daemon.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / libsystemd / sd-daemon / sd-daemon.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <limits.h>
23 #include <mqueue.h>
24 #include <netinet/in.h>
25 #include <stdarg.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/socket.h>
31 #include <sys/stat.h>
32 #include <sys/un.h>
33 #include <unistd.h>
34
35 #include "sd-daemon.h"
36
37 #include "alloc-util.h"
38 #include "fd-util.h"
39 #include "fs-util.h"
40 #include "parse-util.h"
41 #include "path-util.h"
42 #include "socket-util.h"
43 #include "strv.h"
44 #include "util.h"
45
46 #define SNDBUF_SIZE (8*1024*1024)
47
48 static void unsetenv_all(bool unset_environment) {
49
50 if (!unset_environment)
51 return;
52
53 unsetenv("LISTEN_PID");
54 unsetenv("LISTEN_FDS");
55 unsetenv("LISTEN_FDNAMES");
56 }
57
58 _public_ int sd_listen_fds(int unset_environment) {
59 const char *e;
60 int n, r, fd;
61 pid_t pid;
62
63 e = getenv("LISTEN_PID");
64 if (!e) {
65 r = 0;
66 goto finish;
67 }
68
69 r = parse_pid(e, &pid);
70 if (r < 0)
71 goto finish;
72
73 /* Is this for us? */
74 if (getpid_cached() != pid) {
75 r = 0;
76 goto finish;
77 }
78
79 e = getenv("LISTEN_FDS");
80 if (!e) {
81 r = 0;
82 goto finish;
83 }
84
85 r = safe_atoi(e, &n);
86 if (r < 0)
87 goto finish;
88
89 assert_cc(SD_LISTEN_FDS_START < INT_MAX);
90 if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) {
91 r = -EINVAL;
92 goto finish;
93 }
94
95 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
96 r = fd_cloexec(fd, true);
97 if (r < 0)
98 goto finish;
99 }
100
101 r = n;
102
103 finish:
104 unsetenv_all(unset_environment);
105 return r;
106 }
107
108 _public_ int sd_listen_fds_with_names(int unset_environment, char ***names) {
109 _cleanup_strv_free_ char **l = NULL;
110 bool have_names;
111 int n_names = 0, n_fds;
112 const char *e;
113 int r;
114
115 if (!names)
116 return sd_listen_fds(unset_environment);
117
118 e = getenv("LISTEN_FDNAMES");
119 if (e) {
120 n_names = strv_split_extract(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
121 if (n_names < 0) {
122 unsetenv_all(unset_environment);
123 return n_names;
124 }
125
126 have_names = true;
127 } else
128 have_names = false;
129
130 n_fds = sd_listen_fds(unset_environment);
131 if (n_fds <= 0)
132 return n_fds;
133
134 if (have_names) {
135 if (n_names != n_fds)
136 return -EINVAL;
137 } else {
138 r = strv_extend_n(&l, "unknown", n_fds);
139 if (r < 0)
140 return r;
141 }
142
143 *names = l;
144 l = NULL;
145
146 return n_fds;
147 }
148
149 _public_ int sd_is_fifo(int fd, const char *path) {
150 struct stat st_fd;
151
152 assert_return(fd >= 0, -EBADF);
153
154 if (fstat(fd, &st_fd) < 0)
155 return -errno;
156
157 if (!S_ISFIFO(st_fd.st_mode))
158 return 0;
159
160 if (path) {
161 struct stat st_path;
162
163 if (stat(path, &st_path) < 0) {
164
165 if (IN_SET(errno, ENOENT, ENOTDIR))
166 return 0;
167
168 return -errno;
169 }
170
171 return
172 st_path.st_dev == st_fd.st_dev &&
173 st_path.st_ino == st_fd.st_ino;
174 }
175
176 return 1;
177 }
178
179 _public_ int sd_is_special(int fd, const char *path) {
180 struct stat st_fd;
181
182 assert_return(fd >= 0, -EBADF);
183
184 if (fstat(fd, &st_fd) < 0)
185 return -errno;
186
187 if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
188 return 0;
189
190 if (path) {
191 struct stat st_path;
192
193 if (stat(path, &st_path) < 0) {
194
195 if (IN_SET(errno, ENOENT, ENOTDIR))
196 return 0;
197
198 return -errno;
199 }
200
201 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
202 return
203 st_path.st_dev == st_fd.st_dev &&
204 st_path.st_ino == st_fd.st_ino;
205 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
206 return st_path.st_rdev == st_fd.st_rdev;
207 else
208 return 0;
209 }
210
211 return 1;
212 }
213
214 static int sd_is_socket_internal(int fd, int type, int listening) {
215 struct stat st_fd;
216
217 assert_return(fd >= 0, -EBADF);
218 assert_return(type >= 0, -EINVAL);
219
220 if (fstat(fd, &st_fd) < 0)
221 return -errno;
222
223 if (!S_ISSOCK(st_fd.st_mode))
224 return 0;
225
226 if (type != 0) {
227 int other_type = 0;
228 socklen_t l = sizeof(other_type);
229
230 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
231 return -errno;
232
233 if (l != sizeof(other_type))
234 return -EINVAL;
235
236 if (other_type != type)
237 return 0;
238 }
239
240 if (listening >= 0) {
241 int accepting = 0;
242 socklen_t l = sizeof(accepting);
243
244 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
245 return -errno;
246
247 if (l != sizeof(accepting))
248 return -EINVAL;
249
250 if (!accepting != !listening)
251 return 0;
252 }
253
254 return 1;
255 }
256
257 _public_ int sd_is_socket(int fd, int family, int type, int listening) {
258 int r;
259
260 assert_return(fd >= 0, -EBADF);
261 assert_return(family >= 0, -EINVAL);
262
263 r = sd_is_socket_internal(fd, type, listening);
264 if (r <= 0)
265 return r;
266
267 if (family > 0) {
268 union sockaddr_union sockaddr = {};
269 socklen_t l = sizeof(sockaddr);
270
271 if (getsockname(fd, &sockaddr.sa, &l) < 0)
272 return -errno;
273
274 if (l < sizeof(sa_family_t))
275 return -EINVAL;
276
277 return sockaddr.sa.sa_family == family;
278 }
279
280 return 1;
281 }
282
283 _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
284 union sockaddr_union sockaddr = {};
285 socklen_t l = sizeof(sockaddr);
286 int r;
287
288 assert_return(fd >= 0, -EBADF);
289 assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL);
290
291 r = sd_is_socket_internal(fd, type, listening);
292 if (r <= 0)
293 return r;
294
295 if (getsockname(fd, &sockaddr.sa, &l) < 0)
296 return -errno;
297
298 if (l < sizeof(sa_family_t))
299 return -EINVAL;
300
301 if (!IN_SET(sockaddr.sa.sa_family, AF_INET, AF_INET6))
302 return 0;
303
304 if (family != 0)
305 if (sockaddr.sa.sa_family != family)
306 return 0;
307
308 if (port > 0) {
309 if (sockaddr.sa.sa_family == AF_INET) {
310 if (l < sizeof(struct sockaddr_in))
311 return -EINVAL;
312
313 return htobe16(port) == sockaddr.in.sin_port;
314 } else {
315 if (l < sizeof(struct sockaddr_in6))
316 return -EINVAL;
317
318 return htobe16(port) == sockaddr.in6.sin6_port;
319 }
320 }
321
322 return 1;
323 }
324
325 _public_ int sd_is_socket_sockaddr(int fd, int type, const struct sockaddr* addr, unsigned addr_len, int listening) {
326 union sockaddr_union sockaddr = {};
327 socklen_t l = sizeof(sockaddr);
328 int r;
329
330 assert_return(fd >= 0, -EBADF);
331 assert_return(addr, -EINVAL);
332 assert_return(addr_len >= sizeof(sa_family_t), -ENOBUFS);
333 assert_return(IN_SET(addr->sa_family, AF_INET, AF_INET6), -EPFNOSUPPORT);
334
335 r = sd_is_socket_internal(fd, type, listening);
336 if (r <= 0)
337 return r;
338
339 if (getsockname(fd, &sockaddr.sa, &l) < 0)
340 return -errno;
341
342 if (l < sizeof(sa_family_t))
343 return -EINVAL;
344
345 if (sockaddr.sa.sa_family != addr->sa_family)
346 return 0;
347
348 if (sockaddr.sa.sa_family == AF_INET) {
349 const struct sockaddr_in *in = (const struct sockaddr_in *) addr;
350
351 if (l < sizeof(struct sockaddr_in) || addr_len < sizeof(struct sockaddr_in))
352 return -EINVAL;
353
354 if (in->sin_port != 0 &&
355 sockaddr.in.sin_port != in->sin_port)
356 return false;
357
358 return sockaddr.in.sin_addr.s_addr == in->sin_addr.s_addr;
359
360 } else {
361 const struct sockaddr_in6 *in = (const struct sockaddr_in6 *) addr;
362
363 if (l < sizeof(struct sockaddr_in6) || addr_len < sizeof(struct sockaddr_in6))
364 return -EINVAL;
365
366 if (in->sin6_port != 0 &&
367 sockaddr.in6.sin6_port != in->sin6_port)
368 return false;
369
370 if (in->sin6_flowinfo != 0 &&
371 sockaddr.in6.sin6_flowinfo != in->sin6_flowinfo)
372 return false;
373
374 if (in->sin6_scope_id != 0 &&
375 sockaddr.in6.sin6_scope_id != in->sin6_scope_id)
376 return false;
377
378 return memcmp(sockaddr.in6.sin6_addr.s6_addr, in->sin6_addr.s6_addr,
379 sizeof(in->sin6_addr.s6_addr)) == 0;
380 }
381 }
382
383 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
384 union sockaddr_union sockaddr = {};
385 socklen_t l = sizeof(sockaddr);
386 int r;
387
388 assert_return(fd >= 0, -EBADF);
389
390 r = sd_is_socket_internal(fd, type, listening);
391 if (r <= 0)
392 return r;
393
394 if (getsockname(fd, &sockaddr.sa, &l) < 0)
395 return -errno;
396
397 if (l < sizeof(sa_family_t))
398 return -EINVAL;
399
400 if (sockaddr.sa.sa_family != AF_UNIX)
401 return 0;
402
403 if (path) {
404 if (length == 0)
405 length = strlen(path);
406
407 if (length == 0)
408 /* Unnamed socket */
409 return l == offsetof(struct sockaddr_un, sun_path);
410
411 if (path[0])
412 /* Normal path socket */
413 return
414 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
415 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
416 else
417 /* Abstract namespace socket */
418 return
419 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
420 memcmp(path, sockaddr.un.sun_path, length) == 0;
421 }
422
423 return 1;
424 }
425
426 _public_ int sd_is_mq(int fd, const char *path) {
427 struct mq_attr attr;
428
429 /* Check that the fd is valid */
430 assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
431
432 if (mq_getattr(fd, &attr) < 0) {
433 if (errno == EBADF)
434 /* A non-mq fd (or an invalid one, but we ruled that out above) */
435 return 0;
436 return -errno;
437 }
438
439 if (path) {
440 char fpath[PATH_MAX];
441 struct stat a, b;
442
443 assert_return(path_is_absolute(path), -EINVAL);
444
445 if (fstat(fd, &a) < 0)
446 return -errno;
447
448 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
449 fpath[sizeof(fpath)-1] = 0;
450
451 if (stat(fpath, &b) < 0)
452 return -errno;
453
454 if (a.st_dev != b.st_dev ||
455 a.st_ino != b.st_ino)
456 return 0;
457 }
458
459 return 1;
460 }
461
462 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
463 union sockaddr_union sockaddr = {
464 .sa.sa_family = AF_UNIX,
465 };
466 struct iovec iovec = {
467 .iov_base = (char*) state,
468 };
469 struct msghdr msghdr = {
470 .msg_iov = &iovec,
471 .msg_iovlen = 1,
472 .msg_name = &sockaddr,
473 };
474 _cleanup_close_ int fd = -1;
475 struct cmsghdr *cmsg = NULL;
476 const char *e;
477 bool have_pid;
478 int r;
479
480 if (!state) {
481 r = -EINVAL;
482 goto finish;
483 }
484
485 if (n_fds > 0 && !fds) {
486 r = -EINVAL;
487 goto finish;
488 }
489
490 e = getenv("NOTIFY_SOCKET");
491 if (!e)
492 return 0;
493
494 /* Must be an abstract socket, or an absolute path */
495 if (!IN_SET(e[0], '@', '/') || e[1] == 0) {
496 r = -EINVAL;
497 goto finish;
498 }
499
500 if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
501 r = -EINVAL;
502 goto finish;
503 }
504
505 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
506 if (fd < 0) {
507 r = -errno;
508 goto finish;
509 }
510
511 fd_inc_sndbuf(fd, SNDBUF_SIZE);
512
513 iovec.iov_len = strlen(state);
514
515 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
516 if (sockaddr.un.sun_path[0] == '@')
517 sockaddr.un.sun_path[0] = 0;
518
519 msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un);
520
521 have_pid = pid != 0 && pid != getpid_cached();
522
523 if (n_fds > 0 || have_pid) {
524 /* CMSG_SPACE(0) may return value different than zero, which results in miscalculated controllen. */
525 msghdr.msg_controllen =
526 (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
527 (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
528
529 msghdr.msg_control = alloca0(msghdr.msg_controllen);
530
531 cmsg = CMSG_FIRSTHDR(&msghdr);
532 if (n_fds > 0) {
533 cmsg->cmsg_level = SOL_SOCKET;
534 cmsg->cmsg_type = SCM_RIGHTS;
535 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
536
537 memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
538
539 if (have_pid)
540 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
541 }
542
543 if (have_pid) {
544 struct ucred *ucred;
545
546 cmsg->cmsg_level = SOL_SOCKET;
547 cmsg->cmsg_type = SCM_CREDENTIALS;
548 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
549
550 ucred = (struct ucred*) CMSG_DATA(cmsg);
551 ucred->pid = pid;
552 ucred->uid = getuid();
553 ucred->gid = getgid();
554 }
555 }
556
557 /* First try with fake ucred data, as requested */
558 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
559 r = 1;
560 goto finish;
561 }
562
563 /* If that failed, try with our own ucred instead */
564 if (have_pid) {
565 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
566 if (msghdr.msg_controllen == 0)
567 msghdr.msg_control = NULL;
568
569 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
570 r = 1;
571 goto finish;
572 }
573 }
574
575 r = -errno;
576
577 finish:
578 if (unset_environment)
579 unsetenv("NOTIFY_SOCKET");
580
581 return r;
582 }
583
584 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
585 return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
586 }
587
588 _public_ int sd_notify(int unset_environment, const char *state) {
589 return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
590 }
591
592 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
593 _cleanup_free_ char *p = NULL;
594 int r;
595
596 if (format) {
597 va_list ap;
598
599 va_start(ap, format);
600 r = vasprintf(&p, format, ap);
601 va_end(ap);
602
603 if (r < 0 || !p)
604 return -ENOMEM;
605 }
606
607 return sd_pid_notify(pid, unset_environment, p);
608 }
609
610 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
611 _cleanup_free_ char *p = NULL;
612 int r;
613
614 if (format) {
615 va_list ap;
616
617 va_start(ap, format);
618 r = vasprintf(&p, format, ap);
619 va_end(ap);
620
621 if (r < 0 || !p)
622 return -ENOMEM;
623 }
624
625 return sd_pid_notify(0, unset_environment, p);
626 }
627
628 _public_ int sd_booted(void) {
629 /* We test whether the runtime unit file directory has been
630 * created. This takes place in mount-setup.c, so is
631 * guaranteed to happen very early during boot. */
632
633 return laccess("/run/systemd/system/", F_OK) >= 0;
634 }
635
636 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
637 const char *s, *p = ""; /* p is set to dummy value to do unsetting */
638 uint64_t u;
639 int r = 0;
640
641 s = getenv("WATCHDOG_USEC");
642 if (!s)
643 goto finish;
644
645 r = safe_atou64(s, &u);
646 if (r < 0)
647 goto finish;
648 if (u <= 0 || u >= USEC_INFINITY) {
649 r = -EINVAL;
650 goto finish;
651 }
652
653 p = getenv("WATCHDOG_PID");
654 if (p) {
655 pid_t pid;
656
657 r = parse_pid(p, &pid);
658 if (r < 0)
659 goto finish;
660
661 /* Is this for us? */
662 if (getpid_cached() != pid) {
663 r = 0;
664 goto finish;
665 }
666 }
667
668 if (usec)
669 *usec = u;
670
671 r = 1;
672
673 finish:
674 if (unset_environment && s)
675 unsetenv("WATCHDOG_USEC");
676 if (unset_environment && p)
677 unsetenv("WATCHDOG_PID");
678
679 return r;
680 }