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