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