chiark / gitweb /
sd-daemon: use sockaddr_port() helper
[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                 unsigned sa_port;
313
314                 r = sockaddr_port(&sockaddr.sa, &sa_port);
315                 if (r < 0)
316                         return r;
317
318                 return port == sa_port;
319         }
320
321         return 1;
322 }
323
324 _public_ int sd_is_socket_sockaddr(int fd, int type, const struct sockaddr* addr, unsigned addr_len, int listening) {
325         union sockaddr_union sockaddr = {};
326         socklen_t l = sizeof(sockaddr);
327         int r;
328
329         assert_return(fd >= 0, -EBADF);
330         assert_return(addr, -EINVAL);
331         assert_return(addr_len >= sizeof(sa_family_t), -ENOBUFS);
332         assert_return(IN_SET(addr->sa_family, AF_INET, AF_INET6), -EPFNOSUPPORT);
333
334         r = sd_is_socket_internal(fd, type, listening);
335         if (r <= 0)
336                 return r;
337
338         if (getsockname(fd, &sockaddr.sa, &l) < 0)
339                 return -errno;
340
341         if (l < sizeof(sa_family_t))
342                 return -EINVAL;
343
344         if (sockaddr.sa.sa_family != addr->sa_family)
345                 return 0;
346
347         if (sockaddr.sa.sa_family == AF_INET) {
348                 const struct sockaddr_in *in = (const struct sockaddr_in *) addr;
349
350                 if (l < sizeof(struct sockaddr_in) || addr_len < sizeof(struct sockaddr_in))
351                         return -EINVAL;
352
353                 if (in->sin_port != 0 &&
354                     sockaddr.in.sin_port != in->sin_port)
355                         return false;
356
357                 return sockaddr.in.sin_addr.s_addr == in->sin_addr.s_addr;
358
359         } else {
360                 const struct sockaddr_in6 *in = (const struct sockaddr_in6 *) addr;
361
362                 if (l < sizeof(struct sockaddr_in6) || addr_len < sizeof(struct sockaddr_in6))
363                         return -EINVAL;
364
365                 if (in->sin6_port != 0 &&
366                     sockaddr.in6.sin6_port != in->sin6_port)
367                         return false;
368
369                 if (in->sin6_flowinfo != 0 &&
370                     sockaddr.in6.sin6_flowinfo != in->sin6_flowinfo)
371                         return false;
372
373                 if (in->sin6_scope_id != 0 &&
374                     sockaddr.in6.sin6_scope_id != in->sin6_scope_id)
375                         return false;
376
377                 return memcmp(sockaddr.in6.sin6_addr.s6_addr, in->sin6_addr.s6_addr,
378                               sizeof(in->sin6_addr.s6_addr)) == 0;
379         }
380 }
381
382 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
383         union sockaddr_union sockaddr = {};
384         socklen_t l = sizeof(sockaddr);
385         int r;
386
387         assert_return(fd >= 0, -EBADF);
388
389         r = sd_is_socket_internal(fd, type, listening);
390         if (r <= 0)
391                 return r;
392
393         if (getsockname(fd, &sockaddr.sa, &l) < 0)
394                 return -errno;
395
396         if (l < sizeof(sa_family_t))
397                 return -EINVAL;
398
399         if (sockaddr.sa.sa_family != AF_UNIX)
400                 return 0;
401
402         if (path) {
403                 if (length == 0)
404                         length = strlen(path);
405
406                 if (length == 0)
407                         /* Unnamed socket */
408                         return l == offsetof(struct sockaddr_un, sun_path);
409
410                 if (path[0])
411                         /* Normal path socket */
412                         return
413                                 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
414                                 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
415                 else
416                         /* Abstract namespace socket */
417                         return
418                                 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
419                                 memcmp(path, sockaddr.un.sun_path, length) == 0;
420         }
421
422         return 1;
423 }
424
425 #if 0 /// UNNEEDED by elogind
426 _public_ int sd_is_mq(int fd, const char *path) {
427         struct mq_attr attr;
428
429         /* Check that the fd is valid */
430         assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
431
432         if (mq_getattr(fd, &attr) < 0) {
433                 if (errno == EBADF)
434                         /* A non-mq fd (or an invalid one, but we ruled that out above) */
435                         return 0;
436                 return -errno;
437         }
438
439         if (path) {
440                 char fpath[PATH_MAX];
441                 struct stat a, b;
442
443                 assert_return(path_is_absolute(path), -EINVAL);
444
445                 if (fstat(fd, &a) < 0)
446                         return -errno;
447
448                 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
449                 fpath[sizeof(fpath)-1] = 0;
450
451                 if (stat(fpath, &b) < 0)
452                         return -errno;
453
454                 if (a.st_dev != b.st_dev ||
455                     a.st_ino != b.st_ino)
456                         return 0;
457         }
458
459         return 1;
460 }
461 #endif // 0
462
463 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
464         union sockaddr_union sockaddr = {
465                 .sa.sa_family = AF_UNIX,
466         };
467         struct iovec iovec = {
468                 .iov_base = (char*) state,
469         };
470         struct msghdr msghdr = {
471                 .msg_iov = &iovec,
472                 .msg_iovlen = 1,
473                 .msg_name = &sockaddr,
474         };
475         _cleanup_close_ int fd = -1;
476         struct cmsghdr *cmsg = NULL;
477         const char *e;
478         bool have_pid;
479         int r;
480
481         if (!state) {
482                 r = -EINVAL;
483                 goto finish;
484         }
485
486         if (n_fds > 0 && !fds) {
487                 r = -EINVAL;
488                 goto finish;
489         }
490
491         e = getenv("NOTIFY_SOCKET");
492         if (!e)
493                 return 0;
494
495         /* Must be an abstract socket, or an absolute path */
496         if (!IN_SET(e[0], '@', '/') || e[1] == 0) {
497                 r = -EINVAL;
498                 goto finish;
499         }
500
501         if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
502                 r = -EINVAL;
503                 goto finish;
504         }
505
506         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
507         if (fd < 0) {
508                 r = -errno;
509                 goto finish;
510         }
511
512         fd_inc_sndbuf(fd, SNDBUF_SIZE);
513
514         iovec.iov_len = strlen(state);
515
516         strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
517         if (sockaddr.un.sun_path[0] == '@')
518                 sockaddr.un.sun_path[0] = 0;
519
520         msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un);
521
522         have_pid = pid != 0 && pid != getpid_cached();
523
524         if (n_fds > 0 || have_pid) {
525                 /* CMSG_SPACE(0) may return value different than zero, which results in miscalculated controllen. */
526                 msghdr.msg_controllen =
527                         (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
528                         (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
529
530                 msghdr.msg_control = alloca0(msghdr.msg_controllen);
531
532                 cmsg = CMSG_FIRSTHDR(&msghdr);
533                 if (n_fds > 0) {
534                         cmsg->cmsg_level = SOL_SOCKET;
535                         cmsg->cmsg_type = SCM_RIGHTS;
536                         cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
537
538                         memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
539
540                         if (have_pid)
541                                 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
542                 }
543
544                 if (have_pid) {
545                         struct ucred *ucred;
546
547                         cmsg->cmsg_level = SOL_SOCKET;
548                         cmsg->cmsg_type = SCM_CREDENTIALS;
549                         cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
550
551                         ucred = (struct ucred*) CMSG_DATA(cmsg);
552                         ucred->pid = pid;
553                         ucred->uid = getuid();
554                         ucred->gid = getgid();
555                 }
556         }
557
558         /* First try with fake ucred data, as requested */
559         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
560                 r = 1;
561                 goto finish;
562         }
563
564         /* If that failed, try with our own ucred instead */
565         if (have_pid) {
566                 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
567                 if (msghdr.msg_controllen == 0)
568                         msghdr.msg_control = NULL;
569
570                 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
571                         r = 1;
572                         goto finish;
573                 }
574         }
575
576         r = -errno;
577
578 finish:
579         if (unset_environment)
580                 unsetenv("NOTIFY_SOCKET");
581
582         return r;
583 }
584
585 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
586         return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
587 }
588
589 _public_ int sd_notify(int unset_environment, const char *state) {
590         return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
591 }
592
593 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
594         _cleanup_free_ char *p = NULL;
595         int r;
596
597         if (format) {
598                 va_list ap;
599
600                 va_start(ap, format);
601                 r = vasprintf(&p, format, ap);
602                 va_end(ap);
603
604                 if (r < 0 || !p)
605                         return -ENOMEM;
606         }
607
608         return sd_pid_notify(pid, unset_environment, p);
609 }
610
611 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
612         _cleanup_free_ char *p = NULL;
613         int r;
614
615         if (format) {
616                 va_list ap;
617
618                 va_start(ap, format);
619                 r = vasprintf(&p, format, ap);
620                 va_end(ap);
621
622                 if (r < 0 || !p)
623                         return -ENOMEM;
624         }
625
626         return sd_pid_notify(0, unset_environment, p);
627 }
628
629 _public_ int sd_booted(void) {
630         /* We test whether the runtime unit file directory has been
631          * created. This takes place in mount-setup.c, so is
632          * guaranteed to happen very early during boot. */
633
634 #if 0 /// elogind is always used without systemd running the show. (Well, it should...)
635         return laccess("/run/systemd/system/", F_OK) >= 0;
636 #else
637         return 0;
638 #endif // 0
639 }
640
641 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
642         const char *s, *p = ""; /* p is set to dummy value to do unsetting */
643         uint64_t u;
644         int r = 0;
645
646         s = getenv("WATCHDOG_USEC");
647         if (!s)
648                 goto finish;
649
650         r = safe_atou64(s, &u);
651         if (r < 0)
652                 goto finish;
653         if (u <= 0 || u >= USEC_INFINITY) {
654                 r = -EINVAL;
655                 goto finish;
656         }
657
658         p = getenv("WATCHDOG_PID");
659         if (p) {
660                 pid_t pid;
661
662                 r = parse_pid(p, &pid);
663                 if (r < 0)
664                         goto finish;
665
666                 /* Is this for us? */
667                 if (getpid_cached() != pid) {
668                         r = 0;
669                         goto finish;
670                 }
671         }
672
673         if (usec)
674                 *usec = u;
675
676         r = 1;
677
678 finish:
679         if (unset_environment && s)
680                 unsetenv("WATCHDOG_USEC");
681         if (unset_environment && p)
682                 unsetenv("WATCHDOG_PID");
683
684         return r;
685 }