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