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