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