1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <sys/prctl.h>
4 #include <sys/wait.h>
5 
6 #include "sd-bus.h"
7 
8 #include "alloc-util.h"
9 #include "bus-common-errors.h"
10 #include "bus-get-properties.h"
11 #include "bus-log-control-api.h"
12 #include "bus-polkit.h"
13 #include "def.h"
14 #include "env-util.h"
15 #include "fd-util.h"
16 #include "float.h"
17 #include "hostname-util.h"
18 #include "import-util.h"
19 #include "machine-pool.h"
20 #include "main-func.h"
21 #include "missing_capability.h"
22 #include "mkdir-label.h"
23 #include "parse-util.h"
24 #include "path-util.h"
25 #include "percent-util.h"
26 #include "process-util.h"
27 #include "service-util.h"
28 #include "signal-util.h"
29 #include "socket-util.h"
30 #include "stat-util.h"
31 #include "string-table.h"
32 #include "strv.h"
33 #include "syslog-util.h"
34 #include "user-util.h"
35 #include "util.h"
36 #include "web-util.h"
37 
38 typedef struct Transfer Transfer;
39 typedef struct Manager Manager;
40 
41 typedef enum TransferType {
42         TRANSFER_IMPORT_TAR,
43         TRANSFER_IMPORT_RAW,
44         TRANSFER_IMPORT_FS,
45         TRANSFER_EXPORT_TAR,
46         TRANSFER_EXPORT_RAW,
47         TRANSFER_PULL_TAR,
48         TRANSFER_PULL_RAW,
49         _TRANSFER_TYPE_MAX,
50         _TRANSFER_TYPE_INVALID = -EINVAL,
51 } TransferType;
52 
53 struct Transfer {
54         Manager *manager;
55 
56         uint32_t id;
57         char *object_path;
58 
59         TransferType type;
60         ImportVerify verify;
61 
62         char *remote;
63         char *local;
64         bool force_local;
65         bool read_only;
66 
67         char *format;
68 
69         pid_t pid;
70 
71         int log_fd;
72 
73         char log_message[LINE_MAX];
74         size_t log_message_size;
75 
76         sd_event_source *pid_event_source;
77         sd_event_source *log_event_source;
78 
79         unsigned n_canceled;
80         unsigned progress_percent;
81 
82         int stdin_fd;
83         int stdout_fd;
84 };
85 
86 struct Manager {
87         sd_event *event;
88         sd_bus *bus;
89 
90         uint32_t current_transfer_id;
91         Hashmap *transfers;
92 
93         Hashmap *polkit_registry;
94 
95         int notify_fd;
96 
97         sd_event_source *notify_event_source;
98 };
99 
100 #define TRANSFERS_MAX 64
101 
102 static const char* const transfer_type_table[_TRANSFER_TYPE_MAX] = {
103         [TRANSFER_IMPORT_TAR] = "import-tar",
104         [TRANSFER_IMPORT_RAW] = "import-raw",
105         [TRANSFER_IMPORT_FS] = "import-fs",
106         [TRANSFER_EXPORT_TAR] = "export-tar",
107         [TRANSFER_EXPORT_RAW] = "export-raw",
108         [TRANSFER_PULL_TAR] = "pull-tar",
109         [TRANSFER_PULL_RAW] = "pull-raw",
110 };
111 
112 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(transfer_type, TransferType);
113 
transfer_unref(Transfer * t)114 static Transfer *transfer_unref(Transfer *t) {
115         if (!t)
116                 return NULL;
117 
118         if (t->manager)
119                 hashmap_remove(t->manager->transfers, UINT32_TO_PTR(t->id));
120 
121         sd_event_source_unref(t->pid_event_source);
122         sd_event_source_unref(t->log_event_source);
123 
124         free(t->remote);
125         free(t->local);
126         free(t->format);
127         free(t->object_path);
128 
129         if (t->pid > 1)
130                 sigkill_wait(t->pid);
131 
132         safe_close(t->log_fd);
133         safe_close(t->stdin_fd);
134         safe_close(t->stdout_fd);
135 
136         return mfree(t);
137 }
138 
139 DEFINE_TRIVIAL_CLEANUP_FUNC(Transfer*, transfer_unref);
140 
transfer_new(Manager * m,Transfer ** ret)141 static int transfer_new(Manager *m, Transfer **ret) {
142         _cleanup_(transfer_unrefp) Transfer *t = NULL;
143         uint32_t id;
144         int r;
145 
146         assert(m);
147         assert(ret);
148 
149         if (hashmap_size(m->transfers) >= TRANSFERS_MAX)
150                 return -E2BIG;
151 
152         t = new(Transfer, 1);
153         if (!t)
154                 return -ENOMEM;
155 
156         *t = (Transfer) {
157                 .type = _TRANSFER_TYPE_INVALID,
158                 .log_fd = -1,
159                 .stdin_fd = -1,
160                 .stdout_fd = -1,
161                 .verify = _IMPORT_VERIFY_INVALID,
162                 .progress_percent= UINT_MAX,
163         };
164 
165         id = m->current_transfer_id + 1;
166 
167         if (asprintf(&t->object_path, "/org/freedesktop/import1/transfer/_%" PRIu32, id) < 0)
168                 return -ENOMEM;
169 
170         r = hashmap_ensure_put(&m->transfers, &trivial_hash_ops, UINT32_TO_PTR(id), t);
171         if (r < 0)
172                 return r;
173 
174         m->current_transfer_id = id;
175 
176         t->manager = m;
177         t->id = id;
178 
179         *ret = TAKE_PTR(t);
180 
181         return 0;
182 }
183 
transfer_percent_as_double(Transfer * t)184 static double transfer_percent_as_double(Transfer *t) {
185         assert(t);
186 
187         if (t->progress_percent == UINT_MAX)
188                 return -DBL_MAX;
189 
190         return (double) t->progress_percent / 100.0;
191 }
192 
transfer_send_log_line(Transfer * t,const char * line)193 static void transfer_send_log_line(Transfer *t, const char *line) {
194         int r, priority = LOG_INFO;
195 
196         assert(t);
197         assert(line);
198 
199         syslog_parse_priority(&line, &priority, true);
200 
201         log_full(priority, "(transfer%" PRIu32 ") %s", t->id, line);
202 
203         r = sd_bus_emit_signal(
204                         t->manager->bus,
205                         t->object_path,
206                         "org.freedesktop.import1.Transfer",
207                         "LogMessage",
208                         "us",
209                         priority,
210                         line);
211         if (r < 0)
212                 log_warning_errno(r, "Cannot emit log message signal, ignoring: %m");
213  }
214 
transfer_send_logs(Transfer * t,bool flush)215 static void transfer_send_logs(Transfer *t, bool flush) {
216         assert(t);
217 
218         /* Try to send out all log messages, if we can. But if we
219          * can't we remove the messages from the buffer, but don't
220          * fail */
221 
222         while (t->log_message_size > 0) {
223                 _cleanup_free_ char *n = NULL;
224                 char *e;
225 
226                 if (t->log_message_size >= sizeof(t->log_message))
227                         e = t->log_message + sizeof(t->log_message);
228                 else {
229                         char *a, *b;
230 
231                         a = memchr(t->log_message, 0, t->log_message_size);
232                         b = memchr(t->log_message, '\n', t->log_message_size);
233 
234                         if (a && b)
235                                 e = a < b ? a : b;
236                         else if (a)
237                                 e = a;
238                         else
239                                 e = b;
240                 }
241 
242                 if (!e) {
243                         if (!flush)
244                                 return;
245 
246                         e = t->log_message + t->log_message_size;
247                 }
248 
249                 n = strndup(t->log_message, e - t->log_message);
250 
251                 /* Skip over NUL and newlines */
252                 while (e < t->log_message + t->log_message_size && IN_SET(*e, 0, '\n'))
253                         e++;
254 
255                 memmove(t->log_message, e, t->log_message + sizeof(t->log_message) - e);
256                 t->log_message_size -= e - t->log_message;
257 
258                 if (!n) {
259                         log_oom();
260                         continue;
261                 }
262 
263                 if (isempty(n))
264                         continue;
265 
266                 transfer_send_log_line(t, n);
267         }
268 }
269 
transfer_finalize(Transfer * t,bool success)270 static int transfer_finalize(Transfer *t, bool success) {
271         int r;
272 
273         assert(t);
274 
275         transfer_send_logs(t, true);
276 
277         r = sd_bus_emit_signal(
278                         t->manager->bus,
279                         "/org/freedesktop/import1",
280                         "org.freedesktop.import1.Manager",
281                         "TransferRemoved",
282                         "uos",
283                         t->id,
284                         t->object_path,
285                         success ? "done" :
286                         t->n_canceled > 0 ? "canceled" : "failed");
287 
288         if (r < 0)
289                 log_error_errno(r, "Cannot emit message: %m");
290 
291         transfer_unref(t);
292         return 0;
293 }
294 
transfer_cancel(Transfer * t)295 static int transfer_cancel(Transfer *t) {
296         int r;
297 
298         assert(t);
299 
300         r = kill_and_sigcont(t->pid, t->n_canceled < 3 ? SIGTERM : SIGKILL);
301         if (r < 0)
302                 return r;
303 
304         t->n_canceled++;
305         return 0;
306 }
307 
transfer_on_pid(sd_event_source * s,const siginfo_t * si,void * userdata)308 static int transfer_on_pid(sd_event_source *s, const siginfo_t *si, void *userdata) {
309         Transfer *t = userdata;
310         bool success = false;
311 
312         assert(s);
313         assert(t);
314 
315         if (si->si_code == CLD_EXITED) {
316                 if (si->si_status != 0)
317                         log_error("Transfer process failed with exit code %i.", si->si_status);
318                 else {
319                         log_debug("Transfer process succeeded.");
320                         success = true;
321                 }
322 
323         } else if (IN_SET(si->si_code, CLD_KILLED, CLD_DUMPED))
324                 log_error("Transfer process terminated by signal %s.", signal_to_string(si->si_status));
325         else
326                 log_error("Transfer process failed due to unknown reason.");
327 
328         t->pid = 0;
329 
330         return transfer_finalize(t, success);
331 }
332 
transfer_on_log(sd_event_source * s,int fd,uint32_t revents,void * userdata)333 static int transfer_on_log(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
334         Transfer *t = userdata;
335         ssize_t l;
336 
337         assert(s);
338         assert(t);
339 
340         l = read(fd, t->log_message + t->log_message_size, sizeof(t->log_message) - t->log_message_size);
341         if (l < 0)
342                 log_error_errno(errno, "Failed to read log message: %m");
343         if (l <= 0) {
344                 /* EOF/read error. We just close the pipe here, and
345                  * close the watch, waiting for the SIGCHLD to arrive,
346                  * before we do anything else. */
347                 t->log_event_source = sd_event_source_unref(t->log_event_source);
348                 return 0;
349         }
350 
351         t->log_message_size += l;
352 
353         transfer_send_logs(t, false);
354 
355         return 0;
356 }
357 
transfer_start(Transfer * t)358 static int transfer_start(Transfer *t) {
359         _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
360         int r;
361 
362         assert(t);
363         assert(t->pid <= 0);
364 
365         if (pipe2(pipefd, O_CLOEXEC) < 0)
366                 return -errno;
367 
368         r = safe_fork("(sd-transfer)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &t->pid);
369         if (r < 0)
370                 return r;
371         if (r == 0) {
372                 const char *cmd[] = {
373                         NULL, /* systemd-import, systemd-import-fs, systemd-export or systemd-pull */
374                         NULL, /* tar, raw  */
375                         NULL, /* --verify= */
376                         NULL, /* verify argument */
377                         NULL, /* maybe --force */
378                         NULL, /* maybe --read-only */
379                         NULL, /* if so: the actual URL */
380                         NULL, /* maybe --format= */
381                         NULL, /* if so: the actual format */
382                         NULL, /* remote */
383                         NULL, /* local */
384                         NULL
385                 };
386                 unsigned k = 0;
387 
388                 /* Child */
389 
390                 pipefd[0] = safe_close(pipefd[0]);
391 
392                 r = rearrange_stdio(TAKE_FD(t->stdin_fd),
393                                     t->stdout_fd < 0 ? pipefd[1] : TAKE_FD(t->stdout_fd),
394                                     pipefd[1]);
395                 TAKE_FD(pipefd[1]);
396                 if (r < 0) {
397                         log_error_errno(r, "Failed to set stdin/stdout/stderr: %m");
398                         _exit(EXIT_FAILURE);
399                 }
400 
401                 if (setenv("SYSTEMD_LOG_TARGET", "console-prefixed", 1) < 0 ||
402                     setenv("NOTIFY_SOCKET", "/run/systemd/import/notify", 1) < 0) {
403                         log_error_errno(errno, "setenv() failed: %m");
404                         _exit(EXIT_FAILURE);
405                 }
406 
407                 r = setenv_systemd_exec_pid(true);
408                 if (r < 0)
409                         log_warning_errno(r, "Failed to update $SYSTEMD_EXEC_PID, ignoring: %m");
410 
411                 switch (t->type) {
412 
413                 case TRANSFER_IMPORT_TAR:
414                 case TRANSFER_IMPORT_RAW:
415                         cmd[k++] = SYSTEMD_IMPORT_PATH;
416                         break;
417 
418                 case TRANSFER_IMPORT_FS:
419                         cmd[k++] = SYSTEMD_IMPORT_FS_PATH;
420                         break;
421 
422                 case TRANSFER_EXPORT_TAR:
423                 case TRANSFER_EXPORT_RAW:
424                         cmd[k++] = SYSTEMD_EXPORT_PATH;
425                         break;
426 
427                 case TRANSFER_PULL_TAR:
428                 case TRANSFER_PULL_RAW:
429                         cmd[k++] = SYSTEMD_PULL_PATH;
430                         break;
431 
432                 default:
433                         assert_not_reached();
434                 }
435 
436                 switch (t->type) {
437 
438                 case TRANSFER_IMPORT_TAR:
439                 case TRANSFER_EXPORT_TAR:
440                 case TRANSFER_PULL_TAR:
441                         cmd[k++] = "tar";
442                         break;
443 
444                 case TRANSFER_IMPORT_RAW:
445                 case TRANSFER_EXPORT_RAW:
446                 case TRANSFER_PULL_RAW:
447                         cmd[k++] = "raw";
448                         break;
449 
450                 case TRANSFER_IMPORT_FS:
451                         cmd[k++] = "run";
452                         break;
453 
454                 default:
455                         break;
456                 }
457 
458                 if (t->verify != _IMPORT_VERIFY_INVALID) {
459                         cmd[k++] = "--verify";
460                         cmd[k++] = import_verify_to_string(t->verify);
461                 }
462 
463                 if (t->force_local)
464                         cmd[k++] = "--force";
465                 if (t->read_only)
466                         cmd[k++] = "--read-only";
467 
468                 if (t->format) {
469                         cmd[k++] = "--format";
470                         cmd[k++] = t->format;
471                 }
472 
473                 if (!IN_SET(t->type, TRANSFER_EXPORT_TAR, TRANSFER_EXPORT_RAW)) {
474                         if (t->remote)
475                                 cmd[k++] = t->remote;
476                         else
477                                 cmd[k++] = "-";
478                 }
479 
480                 if (t->local)
481                         cmd[k++] = t->local;
482                 cmd[k] = NULL;
483 
484                 execv(cmd[0], (char * const *) cmd);
485                 log_error_errno(errno, "Failed to execute %s tool: %m", cmd[0]);
486                 _exit(EXIT_FAILURE);
487         }
488 
489         pipefd[1] = safe_close(pipefd[1]);
490         t->log_fd = TAKE_FD(pipefd[0]);
491 
492         t->stdin_fd = safe_close(t->stdin_fd);
493 
494         r = sd_event_add_child(t->manager->event, &t->pid_event_source,
495                                t->pid, WEXITED, transfer_on_pid, t);
496         if (r < 0)
497                 return r;
498 
499         r = sd_event_add_io(t->manager->event, &t->log_event_source,
500                             t->log_fd, EPOLLIN, transfer_on_log, t);
501         if (r < 0)
502                 return r;
503 
504         /* Make sure always process logging before SIGCHLD */
505         r = sd_event_source_set_priority(t->log_event_source, SD_EVENT_PRIORITY_NORMAL -5);
506         if (r < 0)
507                 return r;
508 
509         r = sd_bus_emit_signal(
510                         t->manager->bus,
511                         "/org/freedesktop/import1",
512                         "org.freedesktop.import1.Manager",
513                         "TransferNew",
514                         "uo",
515                         t->id,
516                         t->object_path);
517         if (r < 0)
518                 return r;
519 
520         return 0;
521 }
522 
manager_unref(Manager * m)523 static Manager *manager_unref(Manager *m) {
524         Transfer *t;
525 
526         if (!m)
527                 return NULL;
528 
529         sd_event_source_unref(m->notify_event_source);
530         safe_close(m->notify_fd);
531 
532         while ((t = hashmap_first(m->transfers)))
533                 transfer_unref(t);
534 
535         hashmap_free(m->transfers);
536 
537         bus_verify_polkit_async_registry_free(m->polkit_registry);
538 
539         m->bus = sd_bus_flush_close_unref(m->bus);
540         sd_event_unref(m->event);
541 
542         return mfree(m);
543 }
544 
545 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref);
546 
manager_on_notify(sd_event_source * s,int fd,uint32_t revents,void * userdata)547 static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
548 
549         char buf[NOTIFY_BUFFER_MAX+1];
550         struct iovec iovec = {
551                 .iov_base = buf,
552                 .iov_len = sizeof(buf)-1,
553         };
554         CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) +
555                          CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)) control;
556         struct msghdr msghdr = {
557                 .msg_iov = &iovec,
558                 .msg_iovlen = 1,
559                 .msg_control = &control,
560                 .msg_controllen = sizeof(control),
561         };
562         struct ucred *ucred;
563         Manager *m = userdata;
564         char *p, *e;
565         Transfer *t;
566         ssize_t n;
567         int r;
568 
569         n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
570         if (n < 0) {
571                 if (ERRNO_IS_TRANSIENT(n))
572                         return 0;
573                 return (int) n;
574         }
575 
576         cmsg_close_all(&msghdr);
577 
578         if (msghdr.msg_flags & MSG_TRUNC) {
579                 log_warning("Got overly long notification datagram, ignoring.");
580                 return 0;
581         }
582 
583         ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
584         if (!ucred || ucred->pid <= 0) {
585                 log_warning("Got notification datagram lacking credential information, ignoring.");
586                 return 0;
587         }
588 
589         HASHMAP_FOREACH(t, m->transfers)
590                 if (ucred->pid == t->pid)
591                         break;
592 
593         if (!t) {
594                 log_warning("Got notification datagram from unexpected peer, ignoring.");
595                 return 0;
596         }
597 
598         buf[n] = 0;
599 
600         p = startswith(buf, "X_IMPORT_PROGRESS=");
601         if (!p) {
602                 p = strstr(buf, "\nX_IMPORT_PROGRESS=");
603                 if (!p)
604                         return 0;
605 
606                 p += 19;
607         }
608 
609         e = strchrnul(p, '\n');
610         *e = 0;
611 
612         r = parse_percent(p);
613         if (r < 0) {
614                 log_warning("Got invalid percent value, ignoring.");
615                 return 0;
616         }
617 
618         t->progress_percent = (unsigned) r;
619 
620         log_debug("Got percentage from client: %u%%", t->progress_percent);
621         return 0;
622 }
623 
manager_new(Manager ** ret)624 static int manager_new(Manager **ret) {
625         _cleanup_(manager_unrefp) Manager *m = NULL;
626         static const union sockaddr_union sa = {
627                 .un.sun_family = AF_UNIX,
628                 .un.sun_path = "/run/systemd/import/notify",
629         };
630         int r;
631 
632         assert(ret);
633 
634         m = new0(Manager, 1);
635         if (!m)
636                 return -ENOMEM;
637 
638         r = sd_event_default(&m->event);
639         if (r < 0)
640                 return r;
641 
642         sd_event_set_watchdog(m->event, true);
643 
644         r = sd_bus_default_system(&m->bus);
645         if (r < 0)
646                 return r;
647 
648         m->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
649         if (m->notify_fd < 0)
650                 return -errno;
651 
652         (void) mkdir_parents_label(sa.un.sun_path, 0755);
653         (void) sockaddr_un_unlink(&sa.un);
654 
655         if (bind(m->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
656                 return -errno;
657 
658         r = setsockopt_int(m->notify_fd, SOL_SOCKET, SO_PASSCRED, true);
659         if (r < 0)
660                 return r;
661 
662         r = sd_event_add_io(m->event, &m->notify_event_source,
663                             m->notify_fd, EPOLLIN, manager_on_notify, m);
664         if (r < 0)
665                 return r;
666 
667         *ret = TAKE_PTR(m);
668 
669         return 0;
670 }
671 
manager_find(Manager * m,TransferType type,const char * remote)672 static Transfer *manager_find(Manager *m, TransferType type, const char *remote) {
673         Transfer *t;
674 
675         assert(m);
676         assert(type >= 0);
677         assert(type < _TRANSFER_TYPE_MAX);
678 
679         HASHMAP_FOREACH(t, m->transfers)
680                 if (t->type == type && streq_ptr(t->remote, remote))
681                         return t;
682 
683         return NULL;
684 }
685 
method_import_tar_or_raw(sd_bus_message * msg,void * userdata,sd_bus_error * error)686 static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
687         _cleanup_(transfer_unrefp) Transfer *t = NULL;
688         int fd, force, read_only, r;
689         const char *local, *object;
690         Manager *m = userdata;
691         TransferType type;
692         struct stat st;
693         uint32_t id;
694 
695         assert(msg);
696         assert(m);
697 
698         r = bus_verify_polkit_async(
699                         msg,
700                         CAP_SYS_ADMIN,
701                         "org.freedesktop.import1.import",
702                         NULL,
703                         false,
704                         UID_INVALID,
705                         &m->polkit_registry,
706                         error);
707         if (r < 0)
708                 return r;
709         if (r == 0)
710                 return 1; /* Will call us back */
711 
712         r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only);
713         if (r < 0)
714                 return r;
715 
716         if (fstat(fd, &st) < 0)
717                 return -errno;
718 
719         if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode))
720                 return -EINVAL;
721 
722         if (!hostname_is_valid(local, 0))
723                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
724                                          "Local name %s is invalid", local);
725 
726         r = setup_machine_directory(error);
727         if (r < 0)
728                 return r;
729 
730         type = streq_ptr(sd_bus_message_get_member(msg), "ImportTar") ?
731                 TRANSFER_IMPORT_TAR : TRANSFER_IMPORT_RAW;
732 
733         r = transfer_new(m, &t);
734         if (r < 0)
735                 return r;
736 
737         t->type = type;
738         t->force_local = force;
739         t->read_only = read_only;
740 
741         t->local = strdup(local);
742         if (!t->local)
743                 return -ENOMEM;
744 
745         t->stdin_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
746         if (t->stdin_fd < 0)
747                 return -errno;
748 
749         r = transfer_start(t);
750         if (r < 0)
751                 return r;
752 
753         object = t->object_path;
754         id = t->id;
755         t = NULL;
756 
757         return sd_bus_reply_method_return(msg, "uo", id, object);
758 }
759 
method_import_fs(sd_bus_message * msg,void * userdata,sd_bus_error * error)760 static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
761         _cleanup_(transfer_unrefp) Transfer *t = NULL;
762         int fd, force, read_only, r;
763         const char *local, *object;
764         Manager *m = userdata;
765         uint32_t id;
766 
767         assert(msg);
768         assert(m);
769 
770         r = bus_verify_polkit_async(
771                         msg,
772                         CAP_SYS_ADMIN,
773                         "org.freedesktop.import1.import",
774                         NULL,
775                         false,
776                         UID_INVALID,
777                         &m->polkit_registry,
778                         error);
779         if (r < 0)
780                 return r;
781         if (r == 0)
782                 return 1; /* Will call us back */
783 
784         r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only);
785         if (r < 0)
786                 return r;
787 
788         r = fd_verify_directory(fd);
789         if (r < 0)
790                 return r;
791 
792         if (!hostname_is_valid(local, 0))
793                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
794                                          "Local name %s is invalid", local);
795 
796         r = setup_machine_directory(error);
797         if (r < 0)
798                 return r;
799 
800         r = transfer_new(m, &t);
801         if (r < 0)
802                 return r;
803 
804         t->type = TRANSFER_IMPORT_FS;
805         t->force_local = force;
806         t->read_only = read_only;
807 
808         t->local = strdup(local);
809         if (!t->local)
810                 return -ENOMEM;
811 
812         t->stdin_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
813         if (t->stdin_fd < 0)
814                 return -errno;
815 
816         r = transfer_start(t);
817         if (r < 0)
818                 return r;
819 
820         object = t->object_path;
821         id = t->id;
822         t = NULL;
823 
824         return sd_bus_reply_method_return(msg, "uo", id, object);
825 }
826 
method_export_tar_or_raw(sd_bus_message * msg,void * userdata,sd_bus_error * error)827 static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
828         _cleanup_(transfer_unrefp) Transfer *t = NULL;
829         int fd, r;
830         const char *local, *object, *format;
831         Manager *m = userdata;
832         TransferType type;
833         struct stat st;
834         uint32_t id;
835 
836         assert(msg);
837         assert(m);
838 
839         r = bus_verify_polkit_async(
840                         msg,
841                         CAP_SYS_ADMIN,
842                         "org.freedesktop.import1.export",
843                         NULL,
844                         false,
845                         UID_INVALID,
846                         &m->polkit_registry,
847                         error);
848         if (r < 0)
849                 return r;
850         if (r == 0)
851                 return 1; /* Will call us back */
852 
853         r = sd_bus_message_read(msg, "shs", &local, &fd, &format);
854         if (r < 0)
855                 return r;
856 
857         if (!hostname_is_valid(local, 0))
858                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
859                                          "Local name %s is invalid", local);
860 
861         if (fstat(fd, &st) < 0)
862                 return -errno;
863 
864         if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode))
865                 return -EINVAL;
866 
867         type = streq_ptr(sd_bus_message_get_member(msg), "ExportTar") ?
868                 TRANSFER_EXPORT_TAR : TRANSFER_EXPORT_RAW;
869 
870         r = transfer_new(m, &t);
871         if (r < 0)
872                 return r;
873 
874         t->type = type;
875 
876         if (!isempty(format)) {
877                 t->format = strdup(format);
878                 if (!t->format)
879                         return -ENOMEM;
880         }
881 
882         t->local = strdup(local);
883         if (!t->local)
884                 return -ENOMEM;
885 
886         t->stdout_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
887         if (t->stdout_fd < 0)
888                 return -errno;
889 
890         r = transfer_start(t);
891         if (r < 0)
892                 return r;
893 
894         object = t->object_path;
895         id = t->id;
896         t = NULL;
897 
898         return sd_bus_reply_method_return(msg, "uo", id, object);
899 }
900 
method_pull_tar_or_raw(sd_bus_message * msg,void * userdata,sd_bus_error * error)901 static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
902         _cleanup_(transfer_unrefp) Transfer *t = NULL;
903         const char *remote, *local, *verify, *object;
904         Manager *m = userdata;
905         ImportVerify v;
906         TransferType type;
907         int force, r;
908         uint32_t id;
909 
910         assert(msg);
911         assert(m);
912 
913         r = bus_verify_polkit_async(
914                         msg,
915                         CAP_SYS_ADMIN,
916                         "org.freedesktop.import1.pull",
917                         NULL,
918                         false,
919                         UID_INVALID,
920                         &m->polkit_registry,
921                         error);
922         if (r < 0)
923                 return r;
924         if (r == 0)
925                 return 1; /* Will call us back */
926 
927         r = sd_bus_message_read(msg, "sssb", &remote, &local, &verify, &force);
928         if (r < 0)
929                 return r;
930 
931         if (!http_url_is_valid(remote) && !file_url_is_valid(remote))
932                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
933                                          "URL %s is invalid", remote);
934 
935         if (isempty(local))
936                 local = NULL;
937         else if (!hostname_is_valid(local, 0))
938                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
939                                          "Local name %s is invalid", local);
940 
941         if (isempty(verify))
942                 v = IMPORT_VERIFY_SIGNATURE;
943         else
944                 v = import_verify_from_string(verify);
945         if (v < 0)
946                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
947                                          "Unknown verification mode %s", verify);
948 
949         r = setup_machine_directory(error);
950         if (r < 0)
951                 return r;
952 
953         type = streq_ptr(sd_bus_message_get_member(msg), "PullTar") ?
954                 TRANSFER_PULL_TAR : TRANSFER_PULL_RAW;
955 
956         if (manager_find(m, type, remote))
957                 return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS,
958                                          "Transfer for %s already in progress.", remote);
959 
960         r = transfer_new(m, &t);
961         if (r < 0)
962                 return r;
963 
964         t->type = type;
965         t->verify = v;
966         t->force_local = force;
967 
968         t->remote = strdup(remote);
969         if (!t->remote)
970                 return -ENOMEM;
971 
972         if (local) {
973                 t->local = strdup(local);
974                 if (!t->local)
975                         return -ENOMEM;
976         }
977 
978         r = transfer_start(t);
979         if (r < 0)
980                 return r;
981 
982         object = t->object_path;
983         id = t->id;
984         t = NULL;
985 
986         return sd_bus_reply_method_return(msg, "uo", id, object);
987 }
988 
method_list_transfers(sd_bus_message * msg,void * userdata,sd_bus_error * error)989 static int method_list_transfers(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
990         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
991         Manager *m = userdata;
992         Transfer *t;
993         int r;
994 
995         assert(msg);
996         assert(m);
997 
998         r = sd_bus_message_new_method_return(msg, &reply);
999         if (r < 0)
1000                 return r;
1001 
1002         r = sd_bus_message_open_container(reply, 'a', "(usssdo)");
1003         if (r < 0)
1004                 return r;
1005 
1006         HASHMAP_FOREACH(t, m->transfers) {
1007 
1008                 r = sd_bus_message_append(
1009                                 reply,
1010                                 "(usssdo)",
1011                                 t->id,
1012                                 transfer_type_to_string(t->type),
1013                                 t->remote,
1014                                 t->local,
1015                                 transfer_percent_as_double(t),
1016                                 t->object_path);
1017                 if (r < 0)
1018                         return r;
1019         }
1020 
1021         r = sd_bus_message_close_container(reply);
1022         if (r < 0)
1023                 return r;
1024 
1025         return sd_bus_send(NULL, reply, NULL);
1026 }
1027 
method_cancel(sd_bus_message * msg,void * userdata,sd_bus_error * error)1028 static int method_cancel(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
1029         Transfer *t = userdata;
1030         int r;
1031 
1032         assert(msg);
1033         assert(t);
1034 
1035         r = bus_verify_polkit_async(
1036                         msg,
1037                         CAP_SYS_ADMIN,
1038                         "org.freedesktop.import1.pull",
1039                         NULL,
1040                         false,
1041                         UID_INVALID,
1042                         &t->manager->polkit_registry,
1043                         error);
1044         if (r < 0)
1045                 return r;
1046         if (r == 0)
1047                 return 1; /* Will call us back */
1048 
1049         r = transfer_cancel(t);
1050         if (r < 0)
1051                 return r;
1052 
1053         return sd_bus_reply_method_return(msg, NULL);
1054 }
1055 
method_cancel_transfer(sd_bus_message * msg,void * userdata,sd_bus_error * error)1056 static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
1057         Manager *m = userdata;
1058         Transfer *t;
1059         uint32_t id;
1060         int r;
1061 
1062         assert(msg);
1063         assert(m);
1064 
1065         r = bus_verify_polkit_async(
1066                         msg,
1067                         CAP_SYS_ADMIN,
1068                         "org.freedesktop.import1.pull",
1069                         NULL,
1070                         false,
1071                         UID_INVALID,
1072                         &m->polkit_registry,
1073                         error);
1074         if (r < 0)
1075                 return r;
1076         if (r == 0)
1077                 return 1; /* Will call us back */
1078 
1079         r = sd_bus_message_read(msg, "u", &id);
1080         if (r < 0)
1081                 return r;
1082         if (id <= 0)
1083                 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid transfer id");
1084 
1085         t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
1086         if (!t)
1087                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_TRANSFER, "No transfer by id %" PRIu32, id);
1088 
1089         r = transfer_cancel(t);
1090         if (r < 0)
1091                 return r;
1092 
1093         return sd_bus_reply_method_return(msg, NULL);
1094 }
1095 
property_get_progress(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)1096 static int property_get_progress(
1097                 sd_bus *bus,
1098                 const char *path,
1099                 const char *interface,
1100                 const char *property,
1101                 sd_bus_message *reply,
1102                 void *userdata,
1103                 sd_bus_error *error) {
1104 
1105         Transfer *t = userdata;
1106 
1107         assert(bus);
1108         assert(reply);
1109         assert(t);
1110 
1111         return sd_bus_message_append(reply, "d", transfer_percent_as_double(t));
1112 }
1113 
1114 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, transfer_type, TransferType);
1115 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_verify, import_verify, ImportVerify);
1116 
transfer_object_find(sd_bus * bus,const char * path,const char * interface,void * userdata,void ** found,sd_bus_error * error)1117 static int transfer_object_find(
1118                 sd_bus *bus,
1119                 const char *path,
1120                 const char *interface,
1121                 void *userdata,
1122                 void **found,
1123                 sd_bus_error *error) {
1124 
1125         Manager *m = userdata;
1126         Transfer *t;
1127         const char *p;
1128         uint32_t id;
1129         int r;
1130 
1131         assert(bus);
1132         assert(path);
1133         assert(interface);
1134         assert(found);
1135         assert(m);
1136 
1137         p = startswith(path, "/org/freedesktop/import1/transfer/_");
1138         if (!p)
1139                 return 0;
1140 
1141         r = safe_atou32(p, &id);
1142         if (r < 0 || id == 0)
1143                 return 0;
1144 
1145         t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
1146         if (!t)
1147                 return 0;
1148 
1149         *found = t;
1150         return 1;
1151 }
1152 
transfer_node_enumerator(sd_bus * bus,const char * path,void * userdata,char *** nodes,sd_bus_error * error)1153 static int transfer_node_enumerator(
1154                 sd_bus *bus,
1155                 const char *path,
1156                 void *userdata,
1157                 char ***nodes,
1158                 sd_bus_error *error) {
1159 
1160         _cleanup_strv_free_ char **l = NULL;
1161         Manager *m = userdata;
1162         Transfer *t;
1163         unsigned k = 0;
1164 
1165         l = new0(char*, hashmap_size(m->transfers) + 1);
1166         if (!l)
1167                 return -ENOMEM;
1168 
1169         HASHMAP_FOREACH(t, m->transfers) {
1170 
1171                 l[k] = strdup(t->object_path);
1172                 if (!l[k])
1173                         return -ENOMEM;
1174 
1175                 k++;
1176         }
1177 
1178         *nodes = TAKE_PTR(l);
1179 
1180         return 1;
1181 }
1182 
1183 static const sd_bus_vtable transfer_vtable[] = {
1184         SD_BUS_VTABLE_START(0),
1185 
1186         SD_BUS_PROPERTY("Id", "u", NULL, offsetof(Transfer, id), SD_BUS_VTABLE_PROPERTY_CONST),
1187         SD_BUS_PROPERTY("Local", "s", NULL, offsetof(Transfer, local), SD_BUS_VTABLE_PROPERTY_CONST),
1188         SD_BUS_PROPERTY("Remote", "s", NULL, offsetof(Transfer, remote), SD_BUS_VTABLE_PROPERTY_CONST),
1189         SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Transfer, type), SD_BUS_VTABLE_PROPERTY_CONST),
1190         SD_BUS_PROPERTY("Verify", "s", property_get_verify, offsetof(Transfer, verify), SD_BUS_VTABLE_PROPERTY_CONST),
1191         SD_BUS_PROPERTY("Progress", "d", property_get_progress, 0, 0),
1192 
1193         SD_BUS_METHOD("Cancel", NULL, NULL, method_cancel, SD_BUS_VTABLE_UNPRIVILEGED),
1194 
1195         SD_BUS_SIGNAL_WITH_NAMES("LogMessage",
1196                                  "us",
1197                                  SD_BUS_PARAM(priority)
1198                                  SD_BUS_PARAM(line),
1199                                  0),
1200 
1201         SD_BUS_VTABLE_END,
1202 };
1203 
1204 static const BusObjectImplementation transfer_object = {
1205         "/org/freedesktop/import1/transfer",
1206         "org.freedesktop.import1.Transfer",
1207         .fallback_vtables = BUS_FALLBACK_VTABLES({transfer_vtable, transfer_object_find}),
1208         .node_enumerator = transfer_node_enumerator,
1209 };
1210 
1211 static const sd_bus_vtable manager_vtable[] = {
1212         SD_BUS_VTABLE_START(0),
1213 
1214         SD_BUS_METHOD_WITH_NAMES("ImportTar",
1215                                  "hsbb",
1216                                  SD_BUS_PARAM(fd)
1217                                  SD_BUS_PARAM(local_name)
1218                                  SD_BUS_PARAM(force)
1219                                  SD_BUS_PARAM(read_only),
1220                                  "uo",
1221                                  SD_BUS_PARAM(transfer_id)
1222                                  SD_BUS_PARAM(transfer_path),
1223                                  method_import_tar_or_raw,
1224                                  SD_BUS_VTABLE_UNPRIVILEGED),
1225         SD_BUS_METHOD_WITH_NAMES("ImportRaw",
1226                                  "hsbb",
1227                                  SD_BUS_PARAM(fd)
1228                                  SD_BUS_PARAM(local_name)
1229                                  SD_BUS_PARAM(force)
1230                                  SD_BUS_PARAM(read_only),
1231                                  "uo",
1232                                  SD_BUS_PARAM(transfer_id)
1233                                  SD_BUS_PARAM(transfer_path),
1234                                  method_import_tar_or_raw,
1235                                  SD_BUS_VTABLE_UNPRIVILEGED),
1236         SD_BUS_METHOD_WITH_NAMES("ImportFileSystem",
1237                                  "hsbb",
1238                                  SD_BUS_PARAM(fd)
1239                                  SD_BUS_PARAM(local_name)
1240                                  SD_BUS_PARAM(force)
1241                                  SD_BUS_PARAM(read_only),
1242                                  "uo",
1243                                  SD_BUS_PARAM(transfer_id)
1244                                  SD_BUS_PARAM(transfer_path),
1245                                  method_import_fs,
1246                                  SD_BUS_VTABLE_UNPRIVILEGED),
1247         SD_BUS_METHOD_WITH_NAMES("ExportTar",
1248                                  "shs",
1249                                  SD_BUS_PARAM(local_name)
1250                                  SD_BUS_PARAM(fd)
1251                                  SD_BUS_PARAM(format),
1252                                  "uo",
1253                                  SD_BUS_PARAM(transfer_id)
1254                                  SD_BUS_PARAM(transfer_path),
1255                                  method_export_tar_or_raw,
1256                                  SD_BUS_VTABLE_UNPRIVILEGED),
1257         SD_BUS_METHOD_WITH_NAMES("ExportRaw",
1258                                  "shs",
1259                                  SD_BUS_PARAM(local_name)
1260                                  SD_BUS_PARAM(fd)
1261                                  SD_BUS_PARAM(format),
1262                                  "uo",
1263                                  SD_BUS_PARAM(transfer_id)
1264                                  SD_BUS_PARAM(transfer_path),
1265                                  method_export_tar_or_raw,
1266                                  SD_BUS_VTABLE_UNPRIVILEGED),
1267         SD_BUS_METHOD_WITH_NAMES("PullTar",
1268                                  "sssb",
1269                                  SD_BUS_PARAM(url)
1270                                  SD_BUS_PARAM(local_name)
1271                                  SD_BUS_PARAM(verify_mode)
1272                                  SD_BUS_PARAM(force),
1273                                  "uo",
1274                                  SD_BUS_PARAM(transfer_id)
1275                                  SD_BUS_PARAM(transfer_path),
1276                                  method_pull_tar_or_raw,
1277                                  SD_BUS_VTABLE_UNPRIVILEGED),
1278         SD_BUS_METHOD_WITH_NAMES("PullRaw",
1279                                  "sssb",
1280                                  SD_BUS_PARAM(url)
1281                                  SD_BUS_PARAM(local_name)
1282                                  SD_BUS_PARAM(verify_mode)
1283                                  SD_BUS_PARAM(force),
1284                                  "uo",
1285                                  SD_BUS_PARAM(transfer_id)
1286                                  SD_BUS_PARAM(transfer_path),
1287                                  method_pull_tar_or_raw,
1288                                  SD_BUS_VTABLE_UNPRIVILEGED),
1289         SD_BUS_METHOD_WITH_NAMES("ListTransfers",
1290                                  NULL,,
1291                                  "a(usssdo)",
1292                                  SD_BUS_PARAM(transfers),
1293                                  method_list_transfers,
1294                                  SD_BUS_VTABLE_UNPRIVILEGED),
1295         SD_BUS_METHOD_WITH_NAMES("CancelTransfer",
1296                                  "u",
1297                                  SD_BUS_PARAM(transfer_id),
1298                                  NULL,,
1299                                  method_cancel_transfer,
1300                                  SD_BUS_VTABLE_UNPRIVILEGED),
1301 
1302         SD_BUS_SIGNAL_WITH_NAMES("TransferNew",
1303                                  "uo",
1304                                  SD_BUS_PARAM(transfer_id)
1305                                  SD_BUS_PARAM(transfer_path),
1306                                  0),
1307         SD_BUS_SIGNAL_WITH_NAMES("TransferRemoved",
1308                                  "uos",
1309                                  SD_BUS_PARAM(transfer_id)
1310                                  SD_BUS_PARAM(transfer_path)
1311                                  SD_BUS_PARAM(result),
1312                                  0),
1313 
1314         SD_BUS_VTABLE_END,
1315 };
1316 
1317 static const BusObjectImplementation manager_object = {
1318         "/org/freedesktop/import1",
1319         "org.freedesktop.import1.Manager",
1320         .vtables = BUS_VTABLES(manager_vtable),
1321         .children = BUS_IMPLEMENTATIONS(&transfer_object),
1322 };
1323 
manager_add_bus_objects(Manager * m)1324 static int manager_add_bus_objects(Manager *m) {
1325         int r;
1326 
1327         assert(m);
1328 
1329         r = bus_add_implementation(m->bus, &manager_object, m);
1330         if (r < 0)
1331                 return r;
1332 
1333         r = bus_log_control_api_register(m->bus);
1334         if (r < 0)
1335                 return r;
1336 
1337         r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.import1", 0, NULL, NULL);
1338         if (r < 0)
1339                 return log_error_errno(r, "Failed to request name: %m");
1340 
1341         r = sd_bus_attach_event(m->bus, m->event, 0);
1342         if (r < 0)
1343                 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1344 
1345         return 0;
1346 }
1347 
manager_check_idle(void * userdata)1348 static bool manager_check_idle(void *userdata) {
1349         Manager *m = userdata;
1350 
1351         return hashmap_isempty(m->transfers);
1352 }
1353 
manager_run(Manager * m)1354 static int manager_run(Manager *m) {
1355         assert(m);
1356 
1357         return bus_event_loop_with_idle(
1358                         m->event,
1359                         m->bus,
1360                         "org.freedesktop.import1",
1361                         DEFAULT_EXIT_USEC,
1362                         manager_check_idle,
1363                         m);
1364 }
1365 
run(int argc,char * argv[])1366 static int run(int argc, char *argv[]) {
1367         _cleanup_(manager_unrefp) Manager *m = NULL;
1368         int r;
1369 
1370         log_setup();
1371 
1372         r = service_parse_argv("systemd-importd.service",
1373                                "VM and container image import and export service.",
1374                                BUS_IMPLEMENTATIONS(&manager_object,
1375                                                    &log_control_object),
1376                                argc, argv);
1377         if (r <= 0)
1378                 return r;
1379 
1380         umask(0022);
1381 
1382         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
1383 
1384         r = manager_new(&m);
1385         if (r < 0)
1386                 return log_error_errno(r, "Failed to allocate manager object: %m");
1387 
1388         r = manager_add_bus_objects(m);
1389         if (r < 0)
1390                 return r;
1391 
1392         r = manager_run(m);
1393         if (r < 0)
1394                 return log_error_errno(r, "Failed to run event loop: %m");
1395 
1396         return 0;
1397 }
1398 
1399 DEFINE_MAIN_FUNCTION(run);
1400