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