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