diff --git a/Makefile-libostree-defines.am b/Makefile-libostree-defines.am index 06035157..43e09281 100644 --- a/Makefile-libostree-defines.am +++ b/Makefile-libostree-defines.am @@ -46,6 +46,8 @@ libostree_public_headers = \ src/libostree/ostree-repo-finder-mount.h \ src/libostree/ostree-repo-finder-override.h \ src/libostree/ostree-kernel-args.h \ + src/libostree/ostree-sign.h \ + src/libostree/ostree-sign-ed25519.h \ $(NULL) # This one is generated via configure.ac, and the gtk-doc diff --git a/Makefile-libostree.am b/Makefile-libostree.am index a7e7e123..96b9249b 100644 --- a/Makefile-libostree.am +++ b/Makefile-libostree.am @@ -95,6 +95,7 @@ libostree_1_la_SOURCES = \ src/libostree/ostree-repo-commit.c \ src/libostree/ostree-repo-pull.c \ src/libostree/ostree-repo-pull-private.h \ + src/libostree/ostree-repo-pull-verify.c \ src/libostree/ostree-repo-libarchive.c \ src/libostree/ostree-repo-prune.c \ src/libostree/ostree-repo-refs.c \ @@ -262,6 +263,20 @@ libostree_1_la_CFLAGS += $(OT_DEP_SELINUX_CFLAGS) libostree_1_la_LIBADD += $(OT_DEP_SELINUX_LIBS) endif +libostree_1_la_SOURCES += \ + src/libostree/ostree-sign.c \ + src/libostree/ostree-sign.h \ + src/libostree/ostree-sign-dummy.c \ + src/libostree/ostree-sign-dummy.h \ + src/libostree/ostree-sign-ed25519.c \ + src/libostree/ostree-sign-ed25519.h \ + $(NULL) + +if USE_LIBSODIUM +libostree_1_la_CFLAGS += $(OT_DEP_LIBSODIUM_CFLAGS) +libostree_1_la_LIBADD += $(OT_DEP_LIBSODIUM_LIBS) +endif # USE_LIBSODIUM + # XXX: work around clang being passed -fstack-clash-protection which it doesn't understand # See: https://bugzilla.redhat.com/show_bug.cgi?id=1672012 INTROSPECTION_SCANNER_ENV = CC=gcc diff --git a/Makefile-man.am b/Makefile-man.am index bc58103b..718e773c 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -32,7 +32,7 @@ ostree-commit.1 ostree-create-usb.1 ostree-export.1 \ ostree-config.1 ostree-diff.1 ostree-find-remotes.1 ostree-fsck.1 \ ostree-init.1 ostree-log.1 ostree-ls.1 ostree-prune.1 ostree-pull-local.1 \ ostree-pull.1 ostree-refs.1 ostree-remote.1 ostree-reset.1 \ -ostree-rev-parse.1 ostree-show.1 ostree-summary.1 \ +ostree-rev-parse.1 ostree-show.1 ostree-sign.1 ostree-summary.1 \ ostree-static-delta.1 if USE_LIBSOUP man1_files += ostree-trivial-httpd.1 diff --git a/Makefile-ostree.am b/Makefile-ostree.am index f861afe4..e5767641 100644 --- a/Makefile-ostree.am +++ b/Makefile-ostree.am @@ -43,6 +43,7 @@ ostree_SOURCES = src/ostree/main.c \ src/ostree/ot-builtin-remote.c \ src/ostree/ot-builtin-reset.c \ src/ostree/ot-builtin-rev-parse.c \ + src/ostree/ot-builtin-sign.c \ src/ostree/ot-builtin-summary.c \ src/ostree/ot-builtin-show.c \ src/ostree/ot-builtin-static-delta.c \ @@ -112,7 +113,6 @@ ostree_SOURCES += \ $(NULL) endif - if USE_CURL_OR_SOUP ostree_SOURCES += src/ostree/ot-remote-builtin-add-cookie.c \ src/ostree/ot-remote-builtin-delete-cookie.c \ @@ -162,3 +162,8 @@ if USE_LIBARCHIVE ostree_CFLAGS += $(OT_DEP_LIBARCHIVE_CFLAGS) ostree_LDADD += $(OT_DEP_LIBARCHIVE_LIBS) endif + +if USE_LIBSODIUM +ostree_CFLAGS += $(OT_DEP_LIBSODIUM_CFLAGS) +ostree_LDADD += $(OT_DEP_LIBSODIUM_LIBS) +endif # USE_LIBSODIUM diff --git a/Makefile-tests.am b/Makefile-tests.am index 83b0f1a2..a4179377 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -102,6 +102,7 @@ _installed_or_uninstalled_test_scripts = \ tests/test-admin-deploy-etcmerge-cornercases.sh \ tests/test-admin-deploy-uboot.sh \ tests/test-admin-deploy-grub2.sh \ + tests/test-admin-deploy-nomerge.sh \ tests/test-admin-deploy-none.sh \ tests/test-admin-deploy-bootid-gc.sh \ tests/test-admin-instutil-set-kargs.sh \ @@ -137,6 +138,10 @@ _installed_or_uninstalled_test_scripts = \ tests/test-summary-collections.sh \ tests/test-pull-collections.sh \ tests/test-config.sh \ + tests/test-signed-commit.sh \ + tests/test-signed-pull.sh \ + tests/test-pre-signed-pull.sh \ + tests/test-signed-pull-summary.sh \ $(NULL) if USE_GPGME @@ -197,6 +202,7 @@ dist_installed_test_data = tests/archive-test.sh \ tests/fah-deltadata-old.tar.xz \ tests/fah-deltadata-new.tar.xz \ tests/ostree-path-traverse.tar.gz \ + tests/pre-signed-pull-data.tar.gz \ tests/libtest-core.sh \ $(NULL) @@ -452,3 +458,10 @@ else endif INSTALL_DATA_HOOKS += install-installed-tests-extra endif + +# Just forward these +build-kola-tests: + $(MAKE) -C tests/kola + +install-kola-tests: + $(MAKE) -C tests/kola install diff --git a/Makefile.in b/Makefile.in index 58410f8b..541e5d4d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -491,24 +491,26 @@ check_PROGRAMS = $(am__EXEEXT_12) $(am__EXEEXT_13) $(am__EXEEXT_14) @USE_LIBMOUNT_TRUE@am__append_43 = $(OT_DEP_LIBMOUNT_LIBS) @USE_SELINUX_TRUE@am__append_44 = $(OT_DEP_SELINUX_CFLAGS) @USE_SELINUX_TRUE@am__append_45 = $(OT_DEP_SELINUX_LIBS) +@USE_LIBSODIUM_TRUE@am__append_46 = $(OT_DEP_LIBSODIUM_CFLAGS) +@USE_LIBSODIUM_TRUE@am__append_47 = $(OT_DEP_LIBSODIUM_LIBS) # When compiling this is set via config.h, but g-ir-scanner can't use that -@BUILDOPT_INTROSPECTION_TRUE@@ENABLE_EXPERIMENTAL_API_TRUE@am__append_46 = -DOSTREE_ENABLE_EXPERIMENTAL_API=1 -@BUILDOPT_INTROSPECTION_TRUE@am__append_47 = OSTree-1.0.gir -@BUILDOPT_INTROSPECTION_TRUE@am__append_48 = OSTree-1.0.gir -@BUILDOPT_INTROSPECTION_TRUE@am__append_49 = OSTree-1.0.typelib -@BUILDOPT_INTROSPECTION_TRUE@am__append_50 = $(gir_DATA) $(typelib_DATA) -@ENABLE_EXPERIMENTAL_API_TRUE@am__append_51 = \ +@BUILDOPT_INTROSPECTION_TRUE@@ENABLE_EXPERIMENTAL_API_TRUE@am__append_48 = -DOSTREE_ENABLE_EXPERIMENTAL_API=1 +@BUILDOPT_INTROSPECTION_TRUE@am__append_49 = OSTree-1.0.gir +@BUILDOPT_INTROSPECTION_TRUE@am__append_50 = OSTree-1.0.gir +@BUILDOPT_INTROSPECTION_TRUE@am__append_51 = OSTree-1.0.typelib +@BUILDOPT_INTROSPECTION_TRUE@am__append_52 = $(gir_DATA) $(typelib_DATA) +@ENABLE_EXPERIMENTAL_API_TRUE@am__append_53 = \ @ENABLE_EXPERIMENTAL_API_TRUE@ $(NULL) -@USE_GPGME_TRUE@am__append_52 = \ +@USE_GPGME_TRUE@am__append_54 = \ @USE_GPGME_TRUE@ src/ostree/ot-builtin-gpg-sign.c \ @USE_GPGME_TRUE@ $(NULL) -@USE_GPGME_TRUE@am__append_53 = \ +@USE_GPGME_TRUE@am__append_55 = \ @USE_GPGME_TRUE@ src/ostree/ot-remote-builtin-gpg-import.c \ @USE_GPGME_TRUE@ $(NULL) -@USE_CURL_OR_SOUP_TRUE@am__append_54 = src/ostree/ot-remote-builtin-add-cookie.c \ +@USE_CURL_OR_SOUP_TRUE@am__append_56 = src/ostree/ot-remote-builtin-add-cookie.c \ @USE_CURL_OR_SOUP_TRUE@ src/ostree/ot-remote-builtin-delete-cookie.c \ @USE_CURL_OR_SOUP_TRUE@ src/ostree/ot-remote-builtin-list-cookies.c \ @USE_CURL_OR_SOUP_TRUE@ src/ostree/ot-remote-cookie-util.h \ @@ -516,18 +518,20 @@ check_PROGRAMS = $(am__EXEEXT_12) $(am__EXEEXT_13) $(am__EXEEXT_14) @USE_CURL_OR_SOUP_TRUE@ $(NULL) src/ostree/ot-builtin-pull.c # Eventually once we stop things from using this, we should support disabling this -@USE_LIBSOUP_TRUE@am__append_55 = src/ostree/ot-builtin-trivial-httpd.c -@USE_LIBSOUP_TRUE@am__append_56 = ostree-trivial-httpd +@USE_LIBSOUP_TRUE@am__append_57 = src/ostree/ot-builtin-trivial-httpd.c +@USE_LIBSOUP_TRUE@am__append_58 = ostree-trivial-httpd # This is necessary for the cookie jar bits -@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_57 = $(OT_INTERNAL_SOUP_CFLAGS) -@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_58 = $(OT_INTERNAL_SOUP_LIBS) -@USE_LIBARCHIVE_TRUE@am__append_59 = $(OT_DEP_LIBARCHIVE_CFLAGS) -@USE_LIBARCHIVE_TRUE@am__append_60 = $(OT_DEP_LIBARCHIVE_LIBS) -@BUILDOPT_SYSTEMD_TRUE@am__append_61 = ostree-remount +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_59 = $(OT_INTERNAL_SOUP_CFLAGS) +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_60 = $(OT_INTERNAL_SOUP_LIBS) +@USE_LIBARCHIVE_TRUE@am__append_61 = $(OT_DEP_LIBARCHIVE_CFLAGS) +@USE_LIBARCHIVE_TRUE@am__append_62 = $(OT_DEP_LIBARCHIVE_LIBS) +@USE_LIBSODIUM_TRUE@am__append_63 = $(OT_DEP_LIBSODIUM_CFLAGS) +@USE_LIBSODIUM_TRUE@am__append_64 = $(OT_DEP_LIBSODIUM_LIBS) +@BUILDOPT_SYSTEMD_TRUE@am__append_65 = ostree-remount # It is built anyway as a side-effect of having the symlink in tests/, # and if we declare it here, it gets cleaned up properly -@BUILDOPT_SYSTEMD_FALSE@am__append_62 = ostree-remount +@BUILDOPT_SYSTEMD_FALSE@am__append_66 = ostree-remount # ostree-prepare-root can be used as init in a system without a populated /lib. # To support this use case we need to link statically as we will be unable to @@ -539,66 +543,66 @@ check_PROGRAMS = $(am__EXEEXT_12) $(am__EXEEXT_13) $(am__EXEEXT_14) # to get autotools to install this as an executable but without generating rules # to make it itself which we have specified manually. See # https://lists.gnu.org/archive/html/help-gnu-utils/2007-01/msg00007.html -@BUILDOPT_USE_STATIC_COMPILER_TRUE@am__append_63 = ostree-prepare-root -@BUILDOPT_USE_STATIC_COMPILER_FALSE@am__append_64 = ostree-prepare-root -@BUILDOPT_SYSTEMD_TRUE@am__append_65 = -DHAVE_SYSTEMD=1 +@BUILDOPT_USE_STATIC_COMPILER_TRUE@am__append_67 = ostree-prepare-root +@BUILDOPT_USE_STATIC_COMPILER_FALSE@am__append_68 = ostree-prepare-root +@BUILDOPT_SYSTEMD_TRUE@am__append_69 = -DHAVE_SYSTEMD=1 # This is the "new mode" of using a generator for /var; see # https://github.com/ostreedev/ostree/issues/855 -@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_66 = -DHAVE_SYSTEMD_AND_LIBMOUNT=1 -@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_67 = -DHAVE_SYSTEMD_AND_LIBMOUNT=1 +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_70 = -DHAVE_SYSTEMD_AND_LIBMOUNT=1 +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_71 = -DHAVE_SYSTEMD_AND_LIBMOUNT=1 @BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@systemdsystemgenerator_PROGRAMS = ostree-system-generator$(EXEEXT) -@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_68 = $(systemdsystemgenerator_PROGRAMS) +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_72 = $(systemdsystemgenerator_PROGRAMS) # Allow the distcheck install under $prefix test to pass -@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_69 = --with-systemdsystemgeneratordir='$${libdir}/systemd/system-generators' -@BUILDOPT_FUSE_TRUE@am__append_70 = rofiles-fuse -@BUILDOPT_ASAN_TRUE@am__append_71 = OT_SKIP_READDIR_RAND=1 G_SLICE=always-malloc -@USE_GPGME_TRUE@am__append_72 = \ +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_73 = --with-systemdsystemgeneratordir='$${libdir}/systemd/system-generators' +@BUILDOPT_FUSE_TRUE@am__append_74 = rofiles-fuse +@BUILDOPT_ASAN_TRUE@am__append_75 = OT_SKIP_READDIR_RAND=1 G_SLICE=always-malloc +@USE_GPGME_TRUE@am__append_76 = \ @USE_GPGME_TRUE@ tests/test-remote-gpg-import.sh \ @USE_GPGME_TRUE@ tests/test-gpg-signed-commit.sh \ @USE_GPGME_TRUE@ tests/test-admin-gpg.sh \ @USE_GPGME_TRUE@ $(NULL) -@ENABLE_EXPERIMENTAL_API_TRUE@am__append_73 = $(experimental_test_scripts) -@ENABLE_EXPERIMENTAL_API_FALSE@am__append_74 = $(experimental_test_scripts) -@BUILDOPT_FUSE_TRUE@am__append_75 = tests/test-rofiles-fuse.sh -@BUILDOPT_FUSE_TRUE@am__append_76 = tests/rofiles-fuse-symlink-stamp -@BUILDOPT_FUSE_FALSE@am__append_77 = tests/test-rofiles-fuse.sh -@USE_LIBSOUP_TRUE@am__append_78 = tests/test-remote-cookies.sh -@BUILDOPT_GJS_TRUE@am__append_79 = $(js_tests) $(js_installed_tests) -@BUILDOPT_GJS_FALSE@am__append_80 = $(js_tests) -@BUILDOPT_GJS_FALSE@am__append_81 = $(js_installed_tests) -@ENABLE_INSTALLED_TESTS_FALSE@am__append_82 = -rpath $(abs_builddir) -@USE_GPGME_TRUE@am__append_83 = \ +@ENABLE_EXPERIMENTAL_API_TRUE@am__append_77 = $(experimental_test_scripts) +@ENABLE_EXPERIMENTAL_API_FALSE@am__append_78 = $(experimental_test_scripts) +@BUILDOPT_FUSE_TRUE@am__append_79 = tests/test-rofiles-fuse.sh +@BUILDOPT_FUSE_TRUE@am__append_80 = tests/rofiles-fuse-symlink-stamp +@BUILDOPT_FUSE_FALSE@am__append_81 = tests/test-rofiles-fuse.sh +@USE_LIBSOUP_TRUE@am__append_82 = tests/test-remote-cookies.sh +@BUILDOPT_GJS_TRUE@am__append_83 = $(js_tests) $(js_installed_tests) +@BUILDOPT_GJS_FALSE@am__append_84 = $(js_tests) +@BUILDOPT_GJS_FALSE@am__append_85 = $(js_installed_tests) +@ENABLE_INSTALLED_TESTS_FALSE@am__append_86 = -rpath $(abs_builddir) +@USE_GPGME_TRUE@am__append_87 = \ @USE_GPGME_TRUE@ tests/test-gpg-verify-result \ @USE_GPGME_TRUE@ $(NULL) -@USE_AVAHI_TRUE@am__append_84 = tests/test-repo-finder-avahi -@USE_LIBARCHIVE_TRUE@am__append_85 = tests/test-libarchive-import -@USE_GPGME_TRUE@am__append_86 = \ +@USE_AVAHI_TRUE@am__append_88 = tests/test-repo-finder-avahi +@USE_LIBARCHIVE_TRUE@am__append_89 = tests/test-libarchive-import +@USE_GPGME_TRUE@am__append_90 = \ @USE_GPGME_TRUE@ tests/gpg-verify-data/README.md \ @USE_GPGME_TRUE@ $(NULL) -@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__append_87 = $(_installed_or_uninstalled_test_scripts) -@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__append_88 = $(_installed_or_uninstalled_test_programs) -@ENABLE_INSTALLED_TESTS_TRUE@am__append_89 = install-installed-tests-extra +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__append_91 = $(_installed_or_uninstalled_test_scripts) +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__append_92 = $(_installed_or_uninstalled_test_programs) +@ENABLE_INSTALLED_TESTS_TRUE@am__append_93 = install-installed-tests-extra # Allow the distcheck install under $prefix test to pass -@BUILDOPT_SYSTEMD_TRUE@am__append_90 = --with-systemdsystemunitdir='$${libdir}/systemd/system' +@BUILDOPT_SYSTEMD_TRUE@am__append_94 = --with-systemdsystemunitdir='$${libdir}/systemd/system' # We're using the system grub2-mkconfig generator -@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@am__append_91 = src/boot/grub2/grub2-15_ostree -@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@am__append_92 = install-grub2-config-hook +@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@am__append_95 = src/boot/grub2/grub2-15_ostree +@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@am__append_96 = install-grub2-config-hook # We're using our internal generator -@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_TRUE@am__append_93 = src/boot/grub2/ostree-grub-generator -@ENABLE_MAN_TRUE@@USE_LIBSOUP_TRUE@am__append_94 = ostree-trivial-httpd.1 +@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_TRUE@am__append_97 = src/boot/grub2/ostree-grub-generator +@ENABLE_MAN_TRUE@@USE_LIBSOUP_TRUE@am__append_98 = ostree-trivial-httpd.1 # We still want to distribute the source, even if we are not building it -@ENABLE_MAN_TRUE@@USE_LIBSOUP_FALSE@am__append_95 = man/ostree-trivial-httpd.xml -@BUILDOPT_FUSE_TRUE@@ENABLE_MAN_TRUE@am__append_96 = rofiles-fuse.1 -@ENABLE_MAN_TRUE@@USE_GPGME_TRUE@am__append_97 = ostree-gpg-sign.1 -@ENABLE_MAN_TRUE@am__append_98 = $(man1_MANS:.1=.xml) $(man5_MANS:.5=.xml) -@ENABLE_MAN_TRUE@am__append_99 = \ +@ENABLE_MAN_TRUE@@USE_LIBSOUP_FALSE@am__append_99 = man/ostree-trivial-httpd.xml +@BUILDOPT_FUSE_TRUE@@ENABLE_MAN_TRUE@am__append_100 = rofiles-fuse.1 +@ENABLE_MAN_TRUE@@USE_GPGME_TRUE@am__append_101 = ostree-gpg-sign.1 +@ENABLE_MAN_TRUE@am__append_102 = $(man1_MANS:.1=.xml) $(man5_MANS:.5=.xml) +@ENABLE_MAN_TRUE@am__append_103 = \ @ENABLE_MAN_TRUE@ $(man1_MANS) \ @ENABLE_MAN_TRUE@ $(man5_MANS) \ @ENABLE_MAN_TRUE@ $(NULL) @@ -770,6 +774,7 @@ libglnx_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ @USE_CURL_FALSE@@USE_LIBSOUP_TRUE@ $(am__DEPENDENCIES_2) @USE_LIBMOUNT_TRUE@am__DEPENDENCIES_9 = $(am__DEPENDENCIES_1) @USE_SELINUX_TRUE@am__DEPENDENCIES_10 = $(am__DEPENDENCIES_1) +@USE_LIBSODIUM_TRUE@am__DEPENDENCIES_11 = $(am__DEPENDENCIES_1) libostree_1_la_DEPENDENCIES = libotutil.la libglnx.la libbsdiff.la \ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @@ -777,7 +782,7 @@ libostree_1_la_DEPENDENCIES = libotutil.la libglnx.la libbsdiff.la \ $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_6) $(am__DEPENDENCIES_7) \ $(am__DEPENDENCIES_8) $(am__DEPENDENCIES_9) \ - $(am__DEPENDENCIES_10) + $(am__DEPENDENCIES_10) $(am__DEPENDENCIES_11) am__libostree_1_la_SOURCES_DIST = \ src/libostree/ostree-async-progress.c \ src/libostree/ostree-cmdprivate.h \ @@ -807,6 +812,7 @@ am__libostree_1_la_SOURCES_DIST = \ src/libostree/ostree-repo-commit.c \ src/libostree/ostree-repo-pull.c \ src/libostree/ostree-repo-pull-private.h \ + src/libostree/ostree-repo-pull-verify.c \ src/libostree/ostree-repo-libarchive.c \ src/libostree/ostree-repo-prune.c \ src/libostree/ostree-repo-refs.c \ @@ -872,7 +878,12 @@ am__libostree_1_la_SOURCES_DIST = \ src/libostree/ostree-soup-uri.h \ src/libostree/ostree-soup-uri.c \ src/libostree/ostree-soup-form.c \ - src/libostree/ostree-fetcher-soup.c + src/libostree/ostree-fetcher-soup.c \ + src/libostree/ostree-sign.c src/libostree/ostree-sign.h \ + src/libostree/ostree-sign-dummy.c \ + src/libostree/ostree-sign-dummy.h \ + src/libostree/ostree-sign-ed25519.c \ + src/libostree/ostree-sign-ed25519.h @USE_LIBARCHIVE_TRUE@am__objects_2 = src/libostree/libostree_1_la-ostree-libarchive-input-stream.lo \ @USE_LIBARCHIVE_TRUE@ $(am__objects_1) @HAVE_LIBSOUP_CLIENT_CERTS_TRUE@am__objects_3 = src/libostree/libostree_1_la-ostree-tls-cert-interaction.lo \ @@ -920,6 +931,7 @@ am_libostree_1_la_OBJECTS = \ src/libostree/libostree_1_la-ostree-repo-checkout.lo \ src/libostree/libostree_1_la-ostree-repo-commit.lo \ src/libostree/libostree_1_la-ostree-repo-pull.lo \ + src/libostree/libostree_1_la-ostree-repo-pull-verify.lo \ src/libostree/libostree_1_la-ostree-repo-libarchive.lo \ src/libostree/libostree_1_la-ostree-repo-prune.lo \ src/libostree/libostree_1_la-ostree-repo-refs.lo \ @@ -953,7 +965,11 @@ am_libostree_1_la_OBJECTS = \ $(am__objects_1) $(am__objects_2) $(am__objects_3) \ $(am__objects_5) $(am__objects_6) $(am__objects_7) \ $(am__objects_8) $(am__objects_9) $(am__objects_10) \ - $(am__objects_11) $(am__objects_12) $(am__objects_13) + $(am__objects_11) $(am__objects_12) $(am__objects_13) \ + src/libostree/libostree_1_la-ostree-sign.lo \ + src/libostree/libostree_1_la-ostree-sign-dummy.lo \ + src/libostree/libostree_1_la-ostree-sign-ed25519.lo \ + $(am__objects_1) nodist_libostree_1_la_OBJECTS = \ src/libostree/libostree_1_la-ostree-enumtypes.lo \ $(am__objects_1) @@ -963,10 +979,10 @@ libostree_1_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libostree_1_la_CFLAGS) $(CFLAGS) $(libostree_1_la_LDFLAGS) \ $(LDFLAGS) -o $@ -am__DEPENDENCIES_11 = libglnx.la libotutil.la libostree-1.la \ +am__DEPENDENCIES_12 = libglnx.la libotutil.la libostree-1.la \ $(am__DEPENDENCIES_2) -am__DEPENDENCIES_12 = $(am__DEPENDENCIES_11) $(am__DEPENDENCIES_2) -libostreetest_la_DEPENDENCIES = $(am__DEPENDENCIES_12) +am__DEPENDENCIES_13 = $(am__DEPENDENCIES_12) $(am__DEPENDENCIES_2) +libostreetest_la_DEPENDENCIES = $(am__DEPENDENCIES_13) am_libostreetest_la_OBJECTS = tests/libostreetest_la-libostreetest.lo \ tests/libostreetest_la-test-mock-gio.lo libostreetest_la_OBJECTS = $(am_libostreetest_la_OBJECTS) @@ -1038,7 +1054,7 @@ am__ostree_SOURCES_DIST = src/ostree/main.c \ src/ostree/ot-builtin-ls.c src/ostree/ot-builtin-prune.c \ src/ostree/ot-builtin-refs.c src/ostree/ot-builtin-remote.c \ src/ostree/ot-builtin-reset.c \ - src/ostree/ot-builtin-rev-parse.c \ + src/ostree/ot-builtin-rev-parse.c src/ostree/ot-builtin-sign.c \ src/ostree/ot-builtin-summary.c src/ostree/ot-builtin-show.c \ src/ostree/ot-builtin-static-delta.c src/ostree/ot-main.h \ src/ostree/ot-main.c src/ostree/ot-dump.h src/ostree/ot-dump.c \ @@ -1112,6 +1128,7 @@ am_ostree_OBJECTS = src/ostree/ostree-main.$(OBJEXT) \ src/ostree/ostree-ot-builtin-remote.$(OBJEXT) \ src/ostree/ostree-ot-builtin-reset.$(OBJEXT) \ src/ostree/ostree-ot-builtin-rev-parse.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-sign.$(OBJEXT) \ src/ostree/ostree-ot-builtin-summary.$(OBJEXT) \ src/ostree/ostree-ot-builtin-show.$(OBJEXT) \ src/ostree/ostree-ot-builtin-static-delta.$(OBJEXT) \ @@ -1149,9 +1166,9 @@ am_ostree_OBJECTS = src/ostree/ostree-main.$(OBJEXT) \ nodist_ostree_OBJECTS = src/ostree/ostree-parse-datetime.$(OBJEXT) \ $(am__objects_1) ostree_OBJECTS = $(am_ostree_OBJECTS) $(nodist_ostree_OBJECTS) -ostree_DEPENDENCIES = $(am__DEPENDENCIES_11) libbsdiff.la \ +ostree_DEPENDENCIES = $(am__DEPENDENCIES_12) libbsdiff.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_8) \ - $(am__DEPENDENCIES_4) + $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_11) ostree_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ostree_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ @@ -1187,7 +1204,7 @@ am__ostree_trivial_httpd_SOURCES_DIST = \ @USE_LIBSOUP_TRUE@am_ostree_trivial_httpd_OBJECTS = src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.$(OBJEXT) ostree_trivial_httpd_OBJECTS = $(am_ostree_trivial_httpd_OBJECTS) @USE_LIBSOUP_TRUE@ostree_trivial_httpd_DEPENDENCIES = \ -@USE_LIBSOUP_TRUE@ $(am__DEPENDENCIES_11) $(am__DEPENDENCIES_2) +@USE_LIBSOUP_TRUE@ $(am__DEPENDENCIES_12) $(am__DEPENDENCIES_2) ostree_trivial_httpd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(ostree_trivial_httpd_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -1263,7 +1280,7 @@ am_tests_repo_finder_mount_OBJECTS = \ tests/repo_finder_mount-repo-finder-mount.$(OBJEXT) tests_repo_finder_mount_OBJECTS = \ $(am_tests_repo_finder_mount_OBJECTS) -tests_repo_finder_mount_DEPENDENCIES = $(am__DEPENDENCIES_12) \ +tests_repo_finder_mount_DEPENDENCIES = $(am__DEPENDENCIES_13) \ libostreetest.la tests_repo_finder_mount_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ @@ -1272,8 +1289,8 @@ tests_repo_finder_mount_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ tests_test_basic_c_SOURCES = tests/test-basic-c.c tests_test_basic_c_OBJECTS = \ tests/test_basic_c-test-basic-c.$(OBJEXT) -am__DEPENDENCIES_13 = $(am__DEPENDENCIES_12) libostreetest.la -tests_test_basic_c_DEPENDENCIES = $(am__DEPENDENCIES_13) +am__DEPENDENCIES_14 = $(am__DEPENDENCIES_13) libostreetest.la +tests_test_basic_c_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_basic_c_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_basic_c_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -1282,14 +1299,14 @@ am_tests_test_bloom_OBJECTS = \ src/libostree/tests_test_bloom-ostree-bloom.$(OBJEXT) \ tests/test_bloom-test-bloom.$(OBJEXT) tests_test_bloom_OBJECTS = $(am_tests_test_bloom_OBJECTS) -tests_test_bloom_DEPENDENCIES = $(am__DEPENDENCIES_13) +tests_test_bloom_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_bloom_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_bloom_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ tests_test_bsdiff_SOURCES = tests/test-bsdiff.c tests_test_bsdiff_OBJECTS = tests/test_bsdiff-test-bsdiff.$(OBJEXT) -tests_test_bsdiff_DEPENDENCIES = libbsdiff.la $(am__DEPENDENCIES_13) +tests_test_bsdiff_DEPENDENCIES = libbsdiff.la $(am__DEPENDENCIES_14) tests_test_bsdiff_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_bsdiff_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ @@ -1299,7 +1316,7 @@ am_tests_test_checksum_OBJECTS = \ src/libostree/tests_test_checksum-ostree-varint.$(OBJEXT) \ tests/test_checksum-test-checksum.$(OBJEXT) tests_test_checksum_OBJECTS = $(am_tests_test_checksum_OBJECTS) -tests_test_checksum_DEPENDENCIES = $(am__DEPENDENCIES_13) +tests_test_checksum_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_checksum_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_checksum_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -1311,7 +1328,7 @@ am__tests_test_gpg_verify_result_SOURCES_DIST = \ tests_test_gpg_verify_result_OBJECTS = \ $(am_tests_test_gpg_verify_result_OBJECTS) @USE_GPGME_TRUE@tests_test_gpg_verify_result_DEPENDENCIES = \ -@USE_GPGME_TRUE@ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_3) +@USE_GPGME_TRUE@ $(am__DEPENDENCIES_14) $(am__DEPENDENCIES_3) tests_test_gpg_verify_result_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_gpg_verify_result_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -1320,7 +1337,7 @@ am_tests_test_include_ostree_h_OBJECTS = \ tests/test_include_ostree_h-test-include-ostree-h.$(OBJEXT) tests_test_include_ostree_h_OBJECTS = \ $(am_tests_test_include_ostree_h_OBJECTS) -tests_test_include_ostree_h_DEPENDENCIES = $(am__DEPENDENCIES_13) +tests_test_include_ostree_h_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_include_ostree_h_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_include_ostree_h_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -1329,7 +1346,7 @@ am_tests_test_kargs_OBJECTS = \ src/libostree/tests_test_kargs-ostree-kernel-args.$(OBJEXT) \ tests/test_kargs-test-kargs.$(OBJEXT) tests_test_kargs_OBJECTS = $(am_tests_test_kargs_OBJECTS) -tests_test_kargs_DEPENDENCIES = $(am__DEPENDENCIES_13) +tests_test_kargs_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_kargs_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_kargs_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ @@ -1337,7 +1354,7 @@ tests_test_kargs_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ tests_test_keyfile_utils_SOURCES = tests/test-keyfile-utils.c tests_test_keyfile_utils_OBJECTS = \ tests/test_keyfile_utils-test-keyfile-utils.$(OBJEXT) -tests_test_keyfile_utils_DEPENDENCIES = $(am__DEPENDENCIES_13) +tests_test_keyfile_utils_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_keyfile_utils_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_keyfile_utils_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -1346,7 +1363,7 @@ am_tests_test_libarchive_import_OBJECTS = \ tests/test_libarchive_import-test-libarchive-import.$(OBJEXT) tests_test_libarchive_import_OBJECTS = \ $(am_tests_test_libarchive_import_OBJECTS) -tests_test_libarchive_import_DEPENDENCIES = $(am__DEPENDENCIES_13) \ +tests_test_libarchive_import_DEPENDENCIES = $(am__DEPENDENCIES_14) \ $(am__DEPENDENCIES_1) tests_test_libarchive_import_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ @@ -1358,7 +1375,7 @@ am_tests_test_lzma_OBJECTS = \ src/libostree/tests_test_lzma-ostree-lzma-decompressor.$(OBJEXT) \ tests/test_lzma-test-lzma.$(OBJEXT) tests_test_lzma_OBJECTS = $(am_tests_test_lzma_OBJECTS) -tests_test_lzma_DEPENDENCIES = $(am__DEPENDENCIES_13) \ +tests_test_lzma_DEPENDENCIES = $(am__DEPENDENCIES_14) \ $(am__DEPENDENCIES_1) tests_test_lzma_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ @@ -1367,7 +1384,7 @@ tests_test_lzma_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ tests_test_mutable_tree_SOURCES = tests/test-mutable-tree.c tests_test_mutable_tree_OBJECTS = \ tests/test_mutable_tree-test-mutable-tree.$(OBJEXT) -tests_test_mutable_tree_DEPENDENCIES = $(am__DEPENDENCIES_13) +tests_test_mutable_tree_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_mutable_tree_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_mutable_tree_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -1375,7 +1392,7 @@ tests_test_mutable_tree_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ tests_test_ot_opt_utils_SOURCES = tests/test-ot-opt-utils.c tests_test_ot_opt_utils_OBJECTS = \ tests/test_ot_opt_utils-test-ot-opt-utils.$(OBJEXT) -tests_test_ot_opt_utils_DEPENDENCIES = $(am__DEPENDENCIES_13) +tests_test_ot_opt_utils_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_ot_opt_utils_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_ot_opt_utils_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -1383,7 +1400,7 @@ tests_test_ot_opt_utils_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ tests_test_ot_tool_util_SOURCES = tests/test-ot-tool-util.c tests_test_ot_tool_util_OBJECTS = \ tests/test_ot_tool_util-test-ot-tool-util.$(OBJEXT) -tests_test_ot_tool_util_DEPENDENCIES = $(am__DEPENDENCIES_13) +tests_test_ot_tool_util_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_ot_tool_util_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_ot_tool_util_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -1391,21 +1408,21 @@ tests_test_ot_tool_util_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ tests_test_ot_unix_utils_SOURCES = tests/test-ot-unix-utils.c tests_test_ot_unix_utils_OBJECTS = \ tests/test_ot_unix_utils-test-ot-unix-utils.$(OBJEXT) -tests_test_ot_unix_utils_DEPENDENCIES = $(am__DEPENDENCIES_13) +tests_test_ot_unix_utils_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_ot_unix_utils_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_ot_unix_utils_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ tests_test_pull_c_SOURCES = tests/test-pull-c.c tests_test_pull_c_OBJECTS = tests/test_pull_c-test-pull-c.$(OBJEXT) -tests_test_pull_c_DEPENDENCIES = $(am__DEPENDENCIES_13) +tests_test_pull_c_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_pull_c_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_pull_c_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ tests_test_repo_SOURCES = tests/test-repo.c tests_test_repo_OBJECTS = tests/test_repo-test-repo.$(OBJEXT) -tests_test_repo_DEPENDENCIES = $(am__DEPENDENCIES_13) +tests_test_repo_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_repo_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_repo_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ @@ -1418,7 +1435,7 @@ am__tests_test_repo_finder_avahi_SOURCES_DIST = \ tests_test_repo_finder_avahi_OBJECTS = \ $(am_tests_test_repo_finder_avahi_OBJECTS) @USE_AVAHI_TRUE@tests_test_repo_finder_avahi_DEPENDENCIES = \ -@USE_AVAHI_TRUE@ $(am__DEPENDENCIES_13) +@USE_AVAHI_TRUE@ $(am__DEPENDENCIES_14) tests_test_repo_finder_avahi_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_repo_finder_avahi_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -1426,7 +1443,7 @@ tests_test_repo_finder_avahi_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ am_tests_test_repo_finder_config_OBJECTS = tests/test_repo_finder_config-test-repo-finder-config.$(OBJEXT) tests_test_repo_finder_config_OBJECTS = \ $(am_tests_test_repo_finder_config_OBJECTS) -tests_test_repo_finder_config_DEPENDENCIES = $(am__DEPENDENCIES_13) +tests_test_repo_finder_config_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_repo_finder_config_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_repo_finder_config_CFLAGS) $(CFLAGS) \ @@ -1435,7 +1452,7 @@ am_tests_test_repo_finder_mount_OBJECTS = \ tests/test_repo_finder_mount-test-repo-finder-mount.$(OBJEXT) tests_test_repo_finder_mount_OBJECTS = \ $(am_tests_test_repo_finder_mount_OBJECTS) -tests_test_repo_finder_mount_DEPENDENCIES = $(am__DEPENDENCIES_13) +tests_test_repo_finder_mount_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_repo_finder_mount_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_repo_finder_mount_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -1445,7 +1462,7 @@ am_tests_test_rollsum_OBJECTS = \ tests/test_rollsum-test-rollsum.$(OBJEXT) tests_test_rollsum_OBJECTS = $(am_tests_test_rollsum_OBJECTS) tests_test_rollsum_DEPENDENCIES = $(bupsplitpath) \ - $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_14) $(am__DEPENDENCIES_1) tests_test_rollsum_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_rollsum_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -1455,7 +1472,7 @@ am_tests_test_rollsum_cli_OBJECTS = \ tests/test_rollsum_cli-test-rollsum-cli.$(OBJEXT) tests_test_rollsum_cli_OBJECTS = $(am_tests_test_rollsum_cli_OBJECTS) tests_test_rollsum_cli_DEPENDENCIES = $(bupsplitpath) \ - $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_14) $(am__DEPENDENCIES_1) tests_test_rollsum_cli_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_rollsum_cli_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -1463,7 +1480,7 @@ tests_test_rollsum_cli_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ tests_test_sysroot_c_SOURCES = tests/test-sysroot-c.c tests_test_sysroot_c_OBJECTS = \ tests/test_sysroot_c-test-sysroot-c.$(OBJEXT) -tests_test_sysroot_c_DEPENDENCIES = $(am__DEPENDENCIES_13) +tests_test_sysroot_c_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_sysroot_c_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_sysroot_c_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -1472,7 +1489,7 @@ am_tests_test_varint_OBJECTS = \ src/libostree/tests_test_varint-ostree-varint.$(OBJEXT) \ tests/test_varint-test-varint.$(OBJEXT) tests_test_varint_OBJECTS = $(am_tests_test_varint_OBJECTS) -tests_test_varint_DEPENDENCIES = $(am__DEPENDENCIES_13) +tests_test_varint_DEPENDENCIES = $(am__DEPENDENCIES_14) tests_test_varint_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(tests_test_varint_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ @@ -1563,6 +1580,7 @@ am__depfiles_remade = bsdiff/$(DEPDIR)/libbsdiff_la-bsdiff.Plo \ src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder.Plo \ src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Plo \ src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-prune.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull-verify.Plo \ src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull.Plo \ src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-refs.Plo \ src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation-analysis.Plo \ @@ -1573,6 +1591,9 @@ am__depfiles_remade = bsdiff/$(DEPDIR)/libbsdiff_la-bsdiff.Plo \ src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo.Plo \ src/libostree/$(DEPDIR)/libostree_1_la-ostree-rollsum.Plo \ src/libostree/$(DEPDIR)/libostree_1_la-ostree-sepolicy.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-dummy.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-ed25519.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign.Plo \ src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-form.Plo \ src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-uri.Plo \ src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-cleanup.Plo \ @@ -1645,6 +1666,7 @@ am__depfiles_remade = bsdiff/$(DEPDIR)/libbsdiff_la-bsdiff.Plo \ src/ostree/$(DEPDIR)/ostree-ot-builtin-reset.Po \ src/ostree/$(DEPDIR)/ostree-ot-builtin-rev-parse.Po \ src/ostree/$(DEPDIR)/ostree-ot-builtin-show.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Po \ src/ostree/$(DEPDIR)/ostree-ot-builtin-static-delta.Po \ src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Po \ src/ostree/$(DEPDIR)/ostree-ot-builtin-trivial-httpd.Po \ @@ -2031,6 +2053,7 @@ am__EXEEXT_25 = tests/test-basic.sh tests/test-basic-user.sh \ tests/test-admin-deploy-etcmerge-cornercases.sh \ tests/test-admin-deploy-uboot.sh \ tests/test-admin-deploy-grub2.sh \ + tests/test-admin-deploy-nomerge.sh \ tests/test-admin-deploy-none.sh \ tests/test-admin-deploy-bootid-gc.sh \ tests/test-admin-instutil-set-kargs.sh \ @@ -2053,8 +2076,11 @@ am__EXEEXT_25 = tests/test-basic.sh tests/test-basic-user.sh \ tests/test-repo-finder-mount-integration.sh \ tests/test-summary-collections.sh \ tests/test-pull-collections.sh tests/test-config.sh \ - $(am__EXEEXT_2) $(am__EXEEXT_20) $(am__EXEEXT_22) \ - $(am__append_75) $(am__append_78) $(am__EXEEXT_24) + tests/test-signed-commit.sh tests/test-signed-pull.sh \ + tests/test-pre-signed-pull.sh \ + tests/test-signed-pull-summary.sh $(am__EXEEXT_2) \ + $(am__EXEEXT_20) $(am__EXEEXT_22) $(am__append_79) \ + $(am__append_82) $(am__EXEEXT_24) @ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__EXEEXT_26 = \ @ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@ $(am__EXEEXT_25) am__EXEEXT_27 = $(am__EXEEXT_2) $(am__EXEEXT_26) @@ -2245,6 +2271,8 @@ OT_DEP_LIBARCHIVE_CFLAGS = @OT_DEP_LIBARCHIVE_CFLAGS@ OT_DEP_LIBARCHIVE_LIBS = @OT_DEP_LIBARCHIVE_LIBS@ OT_DEP_LIBMOUNT_CFLAGS = @OT_DEP_LIBMOUNT_CFLAGS@ OT_DEP_LIBMOUNT_LIBS = @OT_DEP_LIBMOUNT_LIBS@ +OT_DEP_LIBSODIUM_CFLAGS = @OT_DEP_LIBSODIUM_CFLAGS@ +OT_DEP_LIBSODIUM_LIBS = @OT_DEP_LIBSODIUM_LIBS@ OT_DEP_LZMA_CFLAGS = @OT_DEP_LZMA_CFLAGS@ OT_DEP_LZMA_LIBS = @OT_DEP_LZMA_LIBS@ OT_DEP_SELINUX_CFLAGS = @OT_DEP_SELINUX_CFLAGS@ @@ -2278,6 +2306,8 @@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YEAR_VERSION = @YEAR_VERSION@ YFLAGS = @YFLAGS@ +_GI_EXP_DATADIR = @_GI_EXP_DATADIR@ +_GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ @@ -2353,21 +2383,21 @@ AM_CFLAGS = -std=gnu99 -fno-strict-aliasing $(WARN_CFLAGS) # Allow the distcheck install under $prefix test to pass AM_DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-man \ - --disable-maintainer-mode $(NULL) $(am__append_69) \ - $(am__append_90) \ + --disable-maintainer-mode $(NULL) $(am__append_73) \ + $(am__append_94) \ BASH_COMPLETIONSDIR='$${datadir}/bash-completion/completions' SUBDIRS = . $(am__append_14) NULL = BUILT_SOURCES = $(nodist_libostree_1_la_SOURCES) MANPAGES = -CLEANFILES = $(am__append_13) $(BUILT_SOURCES) $(am__append_50) \ +CLEANFILES = $(am__append_13) $(BUILT_SOURCES) $(am__append_52) \ src/ostree/parse-datetime.c tests/libreaddir-rand.so \ tests/ostree-symlink-stamp \ tests/ostree-prepare-root-symlink-stamp \ tests/ostree-remount-symlink-stamp \ tests/rofiles-fuse-symlink-stamp tests/ostree \ tests/ostree-prepare-root tests/ostree-remount \ - tests/rofiles-fuse $(am__append_99) + tests/rofiles-fuse $(am__append_103) EXTRA_DIST = $(all_dist_test_scripts) $(all_dist_test_data) autogen.sh \ COPYING README.md $(am__append_15) libglnx/README.md \ libglnx/COPYING libglnx/libglnx.m4 $(NULL) \ @@ -2383,9 +2413,9 @@ EXTRA_DIST = $(all_dist_test_scripts) $(all_dist_test_data) autogen.sh \ src/libostree/ostree-repo-deprecated.h \ src/libostree/ostree-version.h src/ostree/parse-datetime.y \ buildutil/tap-driver.sh buildutil/tap-test tests/glib.supp \ - tests/ostree.supp $(NULL) $(am__append_74) $(am__append_77) \ - $(am__append_80) tests/libtest.sh $(am__append_81) \ - $(am__append_86) tests/libostreetest.h tests/libtest.sh \ + tests/ostree.supp $(NULL) $(am__append_78) $(am__append_81) \ + $(am__append_84) tests/libtest.sh $(am__append_85) \ + $(am__append_90) tests/libostreetest.h tests/libtest.sh \ $(NULL) src/boot/dracut/module-setup.sh \ src/boot/dracut/ostree.conf src/boot/mkinitcpio/ostree \ src/boot/ostree-prepare-root.service \ @@ -2393,25 +2423,25 @@ EXTRA_DIST = $(all_dist_test_scripts) $(all_dist_test_data) autogen.sh \ src/boot/ostree-remount.service \ src/boot/ostree-finalize-staged.service \ src/boot/grub2/grub2-15_ostree \ - src/boot/grub2/ostree-grub-generator $(NULL) $(am__append_95) \ - $(am__append_98) + src/boot/grub2/ostree-grub-generator $(NULL) $(am__append_99) \ + $(am__append_102) bin_SCRIPTS = lib_LTLIBRARIES = libostree-1.la -pkglibexec_SCRIPTS = $(am__append_91) +pkglibexec_SCRIPTS = $(am__append_95) noinst_LTLIBRARIES = $(am__append_1) libglnx.la libbsdiff.la \ libotutil.la $(am__append_18) libostreetest.la privlibdir = $(pkglibdir) privlib_LTLIBRARIES = pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = src/libostree/ostree-1.pc -INTROSPECTION_GIRS = $(am__append_47) +INTROSPECTION_GIRS = $(am__append_49) girdir = $(datadir)/gir-1.0 -gir_DATA = $(am__append_48) +gir_DATA = $(am__append_50) typelibdir = $(libdir)/girepository-1.0 -typelib_DATA = $(am__append_49) +typelib_DATA = $(am__append_51) gsettings_SCHEMAS = ostree_bootdir = $(prefix)/lib/ostree -ostree_boot_SCRIPTS = $(am__append_63) $(am__append_93) +ostree_boot_SCRIPTS = $(am__append_67) $(am__append_97) # We should probably consider flipping the default for DEBUG. Also, # include the builddir in $PATH so we find our just-built ostree @@ -2428,7 +2458,7 @@ AM_TESTS_ENVIRONMENT = G_TEST_SRCDIR="$(abs_srcdir)" \ pwd)$${LD_LIBRARY_PATH:+:$${LD_LIBRARY_PATH}} PATH=$$(cd \ $(top_builddir)/tests && pwd):$${PATH} \ OSTREE_FEATURES="$(OSTREE_FEATURES)" PYTHONUNBUFFERED=1 \ - $(NULL) $(am__append_71) + $(NULL) $(am__append_75) LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/buildutil/tap-driver.sh LOG_COMPILER = $(top_srcdir)/buildutil/tap-test installed_test_LTLIBRARIES = $(am__append_12) @@ -2468,14 +2498,14 @@ all_test_ltlibs = $(test_ltlibraries) $(uninstalled_test_ltlibraries) $(installe # This initializes some more variables # This is a special facility to chain together hooks easily -INSTALL_DATA_HOOKS = install-mkdir-remotes-d-hook $(am__append_89) \ - $(am__append_92) +INSTALL_DATA_HOOKS = install-mkdir-remotes-d-hook $(am__append_93) \ + $(am__append_96) ALL_LOCAL_RULES = tests/libreaddir-rand.so shortened_sysconfdir = $$(echo "$(sysconfdir)" | sed -e 's|^$(prefix)||' -e 's|^/||') OSTREE_GITREV = $(shell cd $(srcdir) && if command -v git >/dev/null 2>&1 && test -d .git; then git describe --abbrev=42 --tags --always HEAD; fi) ACLOCAL_AMFLAGS = -I buildutil -I libglnx ${ACLOCAL_FLAGS} GITIGNOREFILES = aclocal.m4 build-aux/ buildutil/*.m4 config.h.in \ - gtk-doc.make $(am__append_68) + gtk-doc.make $(am__append_72) OT_INTERNAL_GIO_UNIX_CFLAGS = $(OT_DEP_GIO_UNIX_CFLAGS) OT_INTERNAL_GIO_UNIX_LIBS = $(OT_DEP_GIO_UNIX_LIBS) OT_INTERNAL_SOUP_CFLAGS = $(OT_DEP_SOUP_CFLAGS) @@ -2593,6 +2623,8 @@ libostree_public_headers = \ src/libostree/ostree-repo-finder-mount.h \ src/libostree/ostree-repo-finder-override.h \ src/libostree/ostree-kernel-args.h \ + src/libostree/ostree-sign.h \ + src/libostree/ostree-sign-ed25519.h \ $(NULL) @@ -2639,6 +2671,7 @@ libostree_1_la_SOURCES = src/libostree/ostree-async-progress.c \ src/libostree/ostree-repo-commit.c \ src/libostree/ostree-repo-pull.c \ src/libostree/ostree-repo-pull-private.h \ + src/libostree/ostree-repo-pull-verify.c \ src/libostree/ostree-repo-libarchive.c \ src/libostree/ostree-repo-prune.c \ src/libostree/ostree-repo-refs.c \ @@ -2685,7 +2718,11 @@ libostree_1_la_SOURCES = src/libostree/ostree-async-progress.c \ $(am__append_20) $(am__append_21) $(am__append_22) \ $(am__append_23) $(am__append_24) $(am__append_25) \ $(am__append_34) $(am__append_35) $(am__append_38) \ - $(am__append_41) + $(am__append_41) src/libostree/ostree-sign.c \ + src/libostree/ostree-sign.h src/libostree/ostree-sign-dummy.c \ + src/libostree/ostree-sign-dummy.h \ + src/libostree/ostree-sign-ed25519.c \ + src/libostree/ostree-sign-ed25519.h $(NULL) libostree_experimental_headers = \ $(NULL) @@ -2702,14 +2739,15 @@ libostree_1_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/bsdiff \ '-D_OSTREE_PUBLIC=__attribute__((visibility("default"))) \ extern' $(am__append_28) $(am__append_30) $(am__append_32) \ $(am__append_36) $(am__append_39) $(am__append_42) \ - $(am__append_44) + $(am__append_44) $(am__append_46) libostree_1_la_LDFLAGS = -version-number 1:0:0 -Bsymbolic-functions $(addprefix $(wl_versionscript_arg),$(symbol_files)) libostree_1_la_LIBADD = libotutil.la libglnx.la libbsdiff.la \ $(OT_INTERNAL_GIO_UNIX_LIBS) $(OT_INTERNAL_GPGME_LIBS) \ $(OT_DEP_LZMA_LIBS) $(OT_DEP_ZLIB_LIBS) $(OT_DEP_CRYPTO_LIBS) \ $(am__append_27) $(bupsplitpath) $(am__append_29) \ $(am__append_31) $(am__append_33) $(am__append_37) \ - $(am__append_40) $(am__append_43) $(am__append_45) + $(am__append_40) $(am__append_43) $(am__append_45) \ + $(am__append_47) EXTRA_libostree_1_la_DEPENDENCIES = $(symbol_files) # XXX: work around clang being passed -fstack-clash-protection which it doesn't understand @@ -2719,7 +2757,7 @@ INTROSPECTION_SCANNER_ENV = CC=gcc @BUILDOPT_INTROSPECTION_TRUE@OSTree_1_0_gir_INCLUDES = Gio-2.0 @BUILDOPT_INTROSPECTION_TRUE@OSTree_1_0_gir_CFLAGS = \ @BUILDOPT_INTROSPECTION_TRUE@ $(libostree_1_la_CFLAGS) \ -@BUILDOPT_INTROSPECTION_TRUE@ $(am__append_46) +@BUILDOPT_INTROSPECTION_TRUE@ $(am__append_48) @BUILDOPT_INTROSPECTION_TRUE@OSTree_1_0_gir_LIBS = libostree-1.la @BUILDOPT_INTROSPECTION_TRUE@OSTree_1_0_gir_SCANNERFLAGS = --warn-all --identifier-prefix=Ostree --symbol-prefix=ostree $(GI_SCANNERFLAGS) @BUILDOPT_INTROSPECTION_TRUE@OSTree_1_0_gir_FILES = $(libostreeinclude_HEADERS) $(filter-out %-private.h %/ostree-soup-uri.h $(libostree_experimental_headers),$(libostree_1_la_SOURCES)) @@ -2743,13 +2781,13 @@ ostree_SOURCES = src/ostree/main.c src/ostree/ot-builtin-admin.c \ src/ostree/ot-builtin-ls.c src/ostree/ot-builtin-prune.c \ src/ostree/ot-builtin-refs.c src/ostree/ot-builtin-remote.c \ src/ostree/ot-builtin-reset.c \ - src/ostree/ot-builtin-rev-parse.c \ + src/ostree/ot-builtin-rev-parse.c src/ostree/ot-builtin-sign.c \ src/ostree/ot-builtin-summary.c src/ostree/ot-builtin-show.c \ src/ostree/ot-builtin-static-delta.c src/ostree/ot-main.h \ src/ostree/ot-main.c src/ostree/ot-dump.h src/ostree/ot-dump.c \ src/ostree/ot-editor.c src/ostree/ot-editor.h \ - src/ostree/parse-datetime.h $(NULL) $(am__append_51) \ - $(am__append_52) src/ostree/ot-admin-builtin-init-fs.c \ + src/ostree/parse-datetime.h $(NULL) $(am__append_53) \ + $(am__append_54) src/ostree/ot-admin-builtin-init-fs.c \ src/ostree/ot-admin-builtin-diff.c \ src/ostree/ot-admin-builtin-deploy.c \ src/ostree/ot-admin-builtin-finalize-staged.c \ @@ -2777,7 +2815,7 @@ ostree_SOURCES = src/ostree/main.c src/ostree/ot-builtin-admin.c \ src/ostree/ot-remote-builtin-show-url.c \ src/ostree/ot-remote-builtin-refs.c \ src/ostree/ot-remote-builtin-summary.c $(NULL) \ - $(am__append_53) $(am__append_54) $(am__append_55) + $(am__append_55) $(am__append_56) $(am__append_57) nodist_ostree_SOURCES = \ src/ostree/parse-datetime.c \ $(NULL) @@ -2789,10 +2827,11 @@ ostree_bin_shared_cflags = $(AM_CFLAGS) -I$(srcdir)/src/libotutil -I$(srcdir)/sr ostree_bin_shared_ldadd = $(AM_LDFLAGS) libglnx.la libotutil.la libostree-1.la \ $(OT_INTERNAL_GIO_UNIX_LIBS) -ostree_CFLAGS = $(ostree_bin_shared_cflags) $(am__append_57) \ - $(am__append_59) +ostree_CFLAGS = $(ostree_bin_shared_cflags) $(am__append_59) \ + $(am__append_61) $(am__append_63) ostree_LDADD = $(ostree_bin_shared_ldadd) libbsdiff.la \ - $(LIBSYSTEMD_LIBS) $(am__append_58) $(am__append_60) + $(LIBSYSTEMD_LIBS) $(am__append_60) $(am__append_62) \ + $(am__append_64) @USE_LIBSOUP_TRUE@ostree_trivial_httpd_SOURCES = src/ostree/ostree-trivial-httpd.c @USE_LIBSOUP_TRUE@ostree_trivial_httpd_CFLAGS = $(ostree_bin_shared_cflags) $(OT_INTERNAL_SOUP_CFLAGS) @USE_LIBSOUP_TRUE@ostree_trivial_httpd_LDADD = $(ostree_bin_shared_ldadd) $(OT_INTERNAL_SOUP_LIBS) @@ -2801,8 +2840,8 @@ ostree_prepare_root_SOURCES = \ src/switchroot/ostree-prepare-root.c \ $(NULL) -ostree_prepare_root_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_65) \ - $(am__append_66) +ostree_prepare_root_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_69) \ + $(am__append_70) @BUILDOPT_USE_STATIC_COMPILER_FALSE@ostree_prepare_root_CFLAGS = $(AM_CFLAGS) -Isrc/switchroot ostree_remount_SOURCES = \ src/switchroot/ostree-mount-util.h \ @@ -2811,7 +2850,7 @@ ostree_remount_SOURCES = \ ostree_remount_CPPFLAGS = $(AM_CPPFLAGS) \ $(OT_INTERNAL_GIO_UNIX_CFLAGS) -Isrc/switchroot \ - -I$(srcdir)/libglnx $(am__append_67) + -I$(srcdir)/libglnx $(am__append_71) ostree_remount_LDADD = $(AM_LDFLAGS) $(OT_INTERNAL_GIO_UNIX_LIBS) libglnx.la @BUILDOPT_SYSTEMD_TRUE@ostree_prepare_root_LDADD = $(AM_LDFLAGS) $(LIBSYSTEMD_LIBS) @BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ostree_system_generator_SOURCES = src/switchroot/ostree-mount-util.h \ @@ -2828,7 +2867,7 @@ ostree_remount_LDADD = $(AM_LDFLAGS) $(OT_INTERNAL_GIO_UNIX_LIBS) libglnx.la @BUILDOPT_FUSE_TRUE@rofiles_fuse_LDADD = libglnx.la $(BUILDOPT_FUSE_LIBS) $(OT_INTERNAL_GIO_UNIX_LIBS) libostree-1.la uninstalled_test_data = tests/ostree-symlink-stamp \ tests/ostree-prepare-root-symlink-stamp \ - tests/ostree-remount-symlink-stamp $(am__append_76) + tests/ostree-remount-symlink-stamp $(am__append_80) dist_uninstalled_test_scripts = tests/test-symbols.sh tests/coccinelle.sh # This logic implements ENABLE_INSTALLED_TESTS_EXCLUSIVE; see below. @@ -2836,10 +2875,10 @@ dist_uninstalled_test_scripts = tests/test-symbols.sh tests/coccinelle.sh # tests *only* run installed, to avoid having to run them twice in CI. # This overrides the glib-tap.mk emphasis on doing both, if we'd # used e.g. `dist_test_scripts`. -dist_test_scripts = $(NULL) $(am__append_87) +dist_test_scripts = $(NULL) $(am__append_91) test_programs = tests/test-bloom tests/test-repo-finder-config \ - tests/test-repo-finder-mount $(NULL) $(am__append_84) \ - $(am__append_88) + tests/test-repo-finder-mount $(NULL) $(am__append_88) \ + $(am__append_92) _installed_or_uninstalled_test_scripts = tests/test-basic.sh \ tests/test-basic-user.sh tests/test-basic-user-only.sh \ tests/test-basic-root.sh tests/test-pull-subpath.sh \ @@ -2867,6 +2906,7 @@ _installed_or_uninstalled_test_scripts = tests/test-basic.sh \ tests/test-admin-deploy-etcmerge-cornercases.sh \ tests/test-admin-deploy-uboot.sh \ tests/test-admin-deploy-grub2.sh \ + tests/test-admin-deploy-nomerge.sh \ tests/test-admin-deploy-none.sh \ tests/test-admin-deploy-bootid-gc.sh \ tests/test-admin-instutil-set-kargs.sh \ @@ -2888,9 +2928,12 @@ _installed_or_uninstalled_test_scripts = tests/test-basic.sh \ tests/test-remote-add-collections.sh \ tests/test-repo-finder-mount-integration.sh \ tests/test-summary-collections.sh \ - tests/test-pull-collections.sh tests/test-config.sh $(NULL) \ - $(am__append_72) $(am__append_73) $(am__append_75) \ - $(am__append_78) $(am__append_79) + tests/test-pull-collections.sh tests/test-config.sh \ + tests/test-signed-commit.sh tests/test-signed-pull.sh \ + tests/test-pre-signed-pull.sh \ + tests/test-signed-pull-summary.sh $(NULL) $(am__append_76) \ + $(am__append_77) $(am__append_79) $(am__append_82) \ + $(am__append_83) experimental_test_scripts = \ $(NULL) @@ -2918,6 +2961,7 @@ dist_installed_test_data = tests/archive-test.sh \ tests/fah-deltadata-old.tar.xz \ tests/fah-deltadata-new.tar.xz \ tests/ostree-path-traverse.tar.gz \ + tests/pre-signed-pull-data.tar.gz \ tests/libtest-core.sh \ $(NULL) @@ -2968,7 +3012,7 @@ libreaddir_rand_la_LIBADD = \ $(NULL) libreaddir_rand_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version \ - $(am__append_82) + $(am__append_86) _installed_or_uninstalled_test_programs = tests/test-varint \ tests/test-ot-unix-utils tests/test-bsdiff \ tests/test-mutable-tree tests/test-keyfile-utils \ @@ -2976,7 +3020,7 @@ _installed_or_uninstalled_test_programs = tests/test-varint \ tests/test-checksum tests/test-lzma tests/test-rollsum \ tests/test-basic-c tests/test-sysroot-c tests/test-pull-c \ tests/test-repo tests/test-include-ostree-h tests/test-kargs \ - $(am__append_83) $(am__append_85) + $(am__append_87) $(am__append_89) common_tests_cflags = $(ostree_bin_shared_cflags) $(OT_INTERNAL_GIO_UNIX_CFLAGS) -I$(srcdir)/libglnx common_tests_ldadd = $(ostree_bin_shared_ldadd) $(OT_INTERNAL_GIO_UNIX_LIBS) libostreetest_la_SOURCES = tests/libostreetest.c tests/test-mock-gio.c tests/test-mock-gio.h @@ -3096,9 +3140,9 @@ tests_test_lzma_LDADD = $(TESTS_LDADD) $(OT_DEP_LZMA_LIBS) @ENABLE_MAN_TRUE@ ostree-prune.1 ostree-pull-local.1 \ @ENABLE_MAN_TRUE@ ostree-pull.1 ostree-refs.1 ostree-remote.1 \ @ENABLE_MAN_TRUE@ ostree-reset.1 ostree-rev-parse.1 \ -@ENABLE_MAN_TRUE@ ostree-show.1 ostree-summary.1 \ -@ENABLE_MAN_TRUE@ ostree-static-delta.1 $(am__append_94) \ -@ENABLE_MAN_TRUE@ $(am__append_96) $(am__append_97) +@ENABLE_MAN_TRUE@ ostree-show.1 ostree-sign.1 ostree-summary.1 \ +@ENABLE_MAN_TRUE@ ostree-static-delta.1 $(am__append_98) \ +@ENABLE_MAN_TRUE@ $(am__append_100) $(am__append_101) @ENABLE_MAN_TRUE@man5_files = ostree.repo.5 ostree.repo-config.5 @ENABLE_MAN_TRUE@man1_MANS = $(addprefix man/,$(man1_files)) @ENABLE_MAN_TRUE@man5_MANS = $(addprefix man/,$(man5_files)) @@ -3773,6 +3817,9 @@ src/libostree/libostree_1_la-ostree-repo-commit.lo: \ src/libostree/libostree_1_la-ostree-repo-pull.lo: \ src/libostree/$(am__dirstamp) \ src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-pull-verify.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) src/libostree/libostree_1_la-ostree-repo-libarchive.lo: \ src/libostree/$(am__dirstamp) \ src/libostree/$(DEPDIR)/$(am__dirstamp) @@ -3902,6 +3949,15 @@ src/libostree/libostree_1_la-ostree-soup-form.lo: \ src/libostree/libostree_1_la-ostree-fetcher-soup.lo: \ src/libostree/$(am__dirstamp) \ src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-sign.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-sign-dummy.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-sign-ed25519.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) src/libostree/libostree_1_la-ostree-enumtypes.lo: \ src/libostree/$(am__dirstamp) \ src/libostree/$(DEPDIR)/$(am__dirstamp) @@ -4035,6 +4091,9 @@ src/ostree/ostree-ot-builtin-reset.$(OBJEXT): \ src/ostree/ostree-ot-builtin-rev-parse.$(OBJEXT): \ src/ostree/$(am__dirstamp) \ src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-sign.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) src/ostree/ostree-ot-builtin-summary.$(OBJEXT): \ src/ostree/$(am__dirstamp) \ src/ostree/$(DEPDIR)/$(am__dirstamp) @@ -4738,6 +4797,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-prune.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull-verify.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-refs.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation-analysis.Plo@am__quote@ # am--include-marker @@ -4748,6 +4808,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-rollsum.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-sepolicy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-dummy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-ed25519.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-form.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-uri.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-cleanup.Plo@am__quote@ # am--include-marker @@ -4820,6 +4883,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-reset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-rev-parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-show.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-static-delta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-trivial-httpd.Po@am__quote@ # am--include-marker @@ -5119,6 +5183,13 @@ src/libostree/libostree_1_la-ostree-repo-pull.lo: src/libostree/ostree-repo-pull @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-pull.lo `test -f 'src/libostree/ostree-repo-pull.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-pull.c +src/libostree/libostree_1_la-ostree-repo-pull-verify.lo: src/libostree/ostree-repo-pull-verify.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-pull-verify.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull-verify.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-pull-verify.lo `test -f 'src/libostree/ostree-repo-pull-verify.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-pull-verify.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull-verify.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull-verify.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-pull-verify.c' object='src/libostree/libostree_1_la-ostree-repo-pull-verify.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-pull-verify.lo `test -f 'src/libostree/ostree-repo-pull-verify.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-pull-verify.c + src/libostree/libostree_1_la-ostree-repo-libarchive.lo: src/libostree/ostree-repo-libarchive.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-libarchive.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-libarchive.lo `test -f 'src/libostree/ostree-repo-libarchive.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-libarchive.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Plo @@ -5420,6 +5491,27 @@ src/libostree/libostree_1_la-ostree-fetcher-soup.lo: src/libostree/ostree-fetche @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-fetcher-soup.lo `test -f 'src/libostree/ostree-fetcher-soup.c' || echo '$(srcdir)/'`src/libostree/ostree-fetcher-soup.c +src/libostree/libostree_1_la-ostree-sign.lo: src/libostree/ostree-sign.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-sign.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign.Tpo -c -o src/libostree/libostree_1_la-ostree-sign.lo `test -f 'src/libostree/ostree-sign.c' || echo '$(srcdir)/'`src/libostree/ostree-sign.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-sign.c' object='src/libostree/libostree_1_la-ostree-sign.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-sign.lo `test -f 'src/libostree/ostree-sign.c' || echo '$(srcdir)/'`src/libostree/ostree-sign.c + +src/libostree/libostree_1_la-ostree-sign-dummy.lo: src/libostree/ostree-sign-dummy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-sign-dummy.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-dummy.Tpo -c -o src/libostree/libostree_1_la-ostree-sign-dummy.lo `test -f 'src/libostree/ostree-sign-dummy.c' || echo '$(srcdir)/'`src/libostree/ostree-sign-dummy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-dummy.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-dummy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-sign-dummy.c' object='src/libostree/libostree_1_la-ostree-sign-dummy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-sign-dummy.lo `test -f 'src/libostree/ostree-sign-dummy.c' || echo '$(srcdir)/'`src/libostree/ostree-sign-dummy.c + +src/libostree/libostree_1_la-ostree-sign-ed25519.lo: src/libostree/ostree-sign-ed25519.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-sign-ed25519.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-ed25519.Tpo -c -o src/libostree/libostree_1_la-ostree-sign-ed25519.lo `test -f 'src/libostree/ostree-sign-ed25519.c' || echo '$(srcdir)/'`src/libostree/ostree-sign-ed25519.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-ed25519.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-ed25519.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-sign-ed25519.c' object='src/libostree/libostree_1_la-ostree-sign-ed25519.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-sign-ed25519.lo `test -f 'src/libostree/ostree-sign-ed25519.c' || echo '$(srcdir)/'`src/libostree/ostree-sign-ed25519.c + src/libostree/libostree_1_la-ostree-enumtypes.lo: src/libostree/ostree-enumtypes.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-enumtypes.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-enumtypes.Tpo -c -o src/libostree/libostree_1_la-ostree-enumtypes.lo `test -f 'src/libostree/ostree-enumtypes.c' || echo '$(srcdir)/'`src/libostree/ostree-enumtypes.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-enumtypes.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-enumtypes.Plo @@ -5819,6 +5911,20 @@ src/ostree/ostree-ot-builtin-rev-parse.obj: src/ostree/ot-builtin-rev-parse.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-rev-parse.obj `if test -f 'src/ostree/ot-builtin-rev-parse.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-rev-parse.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-rev-parse.c'; fi` +src/ostree/ostree-ot-builtin-sign.o: src/ostree/ot-builtin-sign.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-sign.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Tpo -c -o src/ostree/ostree-ot-builtin-sign.o `test -f 'src/ostree/ot-builtin-sign.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-sign.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-sign.c' object='src/ostree/ostree-ot-builtin-sign.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-sign.o `test -f 'src/ostree/ot-builtin-sign.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-sign.c + +src/ostree/ostree-ot-builtin-sign.obj: src/ostree/ot-builtin-sign.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-sign.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Tpo -c -o src/ostree/ostree-ot-builtin-sign.obj `if test -f 'src/ostree/ot-builtin-sign.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-sign.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-sign.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-sign.c' object='src/ostree/ostree-ot-builtin-sign.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-sign.obj `if test -f 'src/ostree/ot-builtin-sign.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-sign.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-sign.c'; fi` + src/ostree/ostree-ot-builtin-summary.o: src/ostree/ot-builtin-summary.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-summary.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Tpo -c -o src/ostree/ostree-ot-builtin-summary.o `test -f 'src/ostree/ot-builtin-summary.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-summary.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Po @@ -8230,6 +8336,13 @@ tests/test-admin-deploy-grub2.sh.log: tests/test-admin-deploy-grub2.sh --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-deploy-nomerge.sh.log: tests/test-admin-deploy-nomerge.sh + @p='tests/test-admin-deploy-nomerge.sh'; \ + b='tests/test-admin-deploy-nomerge.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) tests/test-admin-deploy-none.sh.log: tests/test-admin-deploy-none.sh @p='tests/test-admin-deploy-none.sh'; \ b='tests/test-admin-deploy-none.sh'; \ @@ -8475,6 +8588,34 @@ tests/test-config.sh.log: tests/test-config.sh --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-signed-commit.sh.log: tests/test-signed-commit.sh + @p='tests/test-signed-commit.sh'; \ + b='tests/test-signed-commit.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-signed-pull.sh.log: tests/test-signed-pull.sh + @p='tests/test-signed-pull.sh'; \ + b='tests/test-signed-pull.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pre-signed-pull.sh.log: tests/test-pre-signed-pull.sh + @p='tests/test-pre-signed-pull.sh'; \ + b='tests/test-pre-signed-pull.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-signed-pull-summary.sh.log: tests/test-signed-pull-summary.sh + @p='tests/test-signed-pull-summary.sh'; \ + b='tests/test-signed-pull-summary.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) tests/test-remote-gpg-import.sh.log: tests/test-remote-gpg-import.sh @p='tests/test-remote-gpg-import.sh'; \ b='tests/test-remote-gpg-import.sh'; \ @@ -8962,6 +9103,7 @@ distclean: distclean-recursive -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-prune.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull-verify.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-refs.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation-analysis.Plo @@ -8972,6 +9114,9 @@ distclean: distclean-recursive -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-rollsum.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sepolicy.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-dummy.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-ed25519.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-form.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-uri.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-cleanup.Plo @@ -9044,6 +9189,7 @@ distclean: distclean-recursive -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-reset.Po -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-rev-parse.Po -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-show.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Po -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-static-delta.Po -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Po -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-trivial-httpd.Po @@ -9230,6 +9376,7 @@ maintainer-clean: maintainer-clean-recursive -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-prune.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull-verify.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-refs.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation-analysis.Plo @@ -9240,6 +9387,9 @@ maintainer-clean: maintainer-clean-recursive -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-rollsum.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sepolicy.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-dummy.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-ed25519.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-form.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-uri.Plo -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-cleanup.Plo @@ -9312,6 +9462,7 @@ maintainer-clean: maintainer-clean-recursive -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-reset.Po -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-rev-parse.Po -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-show.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Po -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-static-delta.Po -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Po -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-trivial-httpd.Po @@ -9568,6 +9719,13 @@ tests/%-symlink-stamp: % Makefile @ENABLE_INSTALLED_TESTS_TRUE@ ln -s . $(DESTDIR)$(installed_testdir)/tests @BUILDOPT_ASAN_TRUE@@ENABLE_INSTALLED_TESTS_TRUE@ sed -e 's,^BUILT_WITH_ASAN=.*,BUILT_WITH_ASAN=1,' < $(srcdir)/tests/libtest.sh > $(DESTDIR)$(installed_testdir)/tests/libtest.sh @BUILDOPT_ASAN_FALSE@@ENABLE_INSTALLED_TESTS_TRUE@ install -m 0644 $(srcdir)/tests/libtest.sh $(DESTDIR)$(installed_testdir)/tests/libtest.sh + +# Just forward these +build-kola-tests: + $(MAKE) -C tests/kola + +install-kola-tests: + $(MAKE) -C tests/kola install @BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@install-grub2-config-hook: @BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@ mkdir -p $(DESTDIR)$(grub2configdir) @BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@ ln -sf $(pkglibexecdir)/grub2-15_ostree $(DESTDIR)$(grub2configdir)/15_ostree diff --git a/README.md b/README.md index 1e6348dd..1ef8e302 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ New! See the docs online at [Read The Docs (OSTree)](https://ostree.readthedocs. Contributing ------------ -See [Contributing](CONTRIBUTING.md). +See [Contributing](docs/CONTRIBUTING.md). Licensing diff --git a/aclocal.m4 b/aclocal.m4 index 46f62182..26d18fbc 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -568,6 +568,47 @@ dnl # serial 1 +dnl This is a copy of AS_AC_EXPAND +dnl +dnl (C) 2003, 2004, 2005 Thomas Vander Stichele +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty provided the copyright +dnl notice and this notice are preserved. +m4_define([_GOBJECT_INTROSPECTION_AS_AC_EXPAND], +[ + EXP_VAR=[$1] + FROM_VAR=[$2] + + dnl first expand prefix and exec_prefix if necessary + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + dnl if no prefix given, then use /usr/local, the default prefix + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + dnl if no exec_prefix given, then use prefix + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + dnl loop until it doesn't change anymore + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + dnl clean up + full_var=$new_full_var + AC_SUBST([$1], "$full_var") + + dnl restore prefix and exec_prefix + prefix=$prefix_save + exec_prefix=$exec_prefix_save +]) + m4_define([_GOBJECT_INTROSPECTION_CHECK_INTERNAL], [ AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first @@ -610,20 +651,25 @@ m4_define([_GOBJECT_INTROSPECTION_CHECK_INTERNAL], AC_MSG_RESULT([$found_introspection]) + dnl expand datadir/libdir so we can pass them to pkg-config + dnl and get paths relative to our target directories + _GOBJECT_INTROSPECTION_AS_AC_EXPAND(_GI_EXP_DATADIR, "$datadir") + _GOBJECT_INTROSPECTION_AS_AC_EXPAND(_GI_EXP_LIBDIR, "$libdir") + INTROSPECTION_SCANNER= INTROSPECTION_COMPILER= INTROSPECTION_GENERATE= INTROSPECTION_GIRDIR= INTROSPECTION_TYPELIBDIR= if test "x$found_introspection" = "xyes"; then - INTROSPECTION_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0` - INTROSPECTION_COMPILER=`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0` - INTROSPECTION_GENERATE=`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0` - INTROSPECTION_GIRDIR=`$PKG_CONFIG --variable=girdir gobject-introspection-1.0` - INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)" + INTROSPECTION_SCANNER=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0` + INTROSPECTION_COMPILER=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0` + INTROSPECTION_GENERATE=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0` + INTROSPECTION_GIRDIR=`$PKG_CONFIG --define-variable=datadir="${_GI_EXP_DATADIR}" --variable=girdir gobject-introspection-1.0` + INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --define-variable=libdir="${_GI_EXP_LIBDIR}" --variable=typelibdir gobject-introspection-1.0)" INTROSPECTION_CFLAGS=`$PKG_CONFIG --cflags gobject-introspection-1.0` INTROSPECTION_LIBS=`$PKG_CONFIG --libs gobject-introspection-1.0` - INTROSPECTION_MAKEFILE=`$PKG_CONFIG --variable=datadir gobject-introspection-1.0`/gobject-introspection-1.0/Makefile.introspection + INTROSPECTION_MAKEFILE=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=datadir gobject-introspection-1.0`/gobject-introspection-1.0/Makefile.introspection fi AC_SUBST(INTROSPECTION_SCANNER) AC_SUBST(INTROSPECTION_COMPILER) diff --git a/apidoc/Makefile.in b/apidoc/Makefile.in index e196f994..db2d7dae 100644 --- a/apidoc/Makefile.in +++ b/apidoc/Makefile.in @@ -295,6 +295,8 @@ OT_DEP_LIBARCHIVE_CFLAGS = @OT_DEP_LIBARCHIVE_CFLAGS@ OT_DEP_LIBARCHIVE_LIBS = @OT_DEP_LIBARCHIVE_LIBS@ OT_DEP_LIBMOUNT_CFLAGS = @OT_DEP_LIBMOUNT_CFLAGS@ OT_DEP_LIBMOUNT_LIBS = @OT_DEP_LIBMOUNT_LIBS@ +OT_DEP_LIBSODIUM_CFLAGS = @OT_DEP_LIBSODIUM_CFLAGS@ +OT_DEP_LIBSODIUM_LIBS = @OT_DEP_LIBSODIUM_LIBS@ OT_DEP_LZMA_CFLAGS = @OT_DEP_LZMA_CFLAGS@ OT_DEP_LZMA_LIBS = @OT_DEP_LZMA_LIBS@ OT_DEP_SELINUX_CFLAGS = @OT_DEP_SELINUX_CFLAGS@ @@ -328,6 +330,8 @@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YEAR_VERSION = @YEAR_VERSION@ YFLAGS = @YFLAGS@ +_GI_EXP_DATADIR = @_GI_EXP_DATADIR@ +_GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ @@ -412,6 +416,8 @@ libostree_public_headers = \ src/libostree/ostree-repo-finder-mount.h \ src/libostree/ostree-repo-finder-override.h \ src/libostree/ostree-kernel-args.h \ + src/libostree/ostree-sign.h \ + src/libostree/ostree-sign-ed25519.h \ $(NULL) diff --git a/apidoc/html/index.html b/apidoc/html/index.html index 4dd0bde2..cbd1e15c 100644 --- a/apidoc/html/index.html +++ b/apidoc/html/index.html @@ -6,7 +6,7 @@ - + @@ -14,7 +14,7 @@
-

for OSTree 2020.3

+

for OSTree 2020.4


@@ -46,6 +46,9 @@ GPG signature verification results — Inspect detached GPG signatures
+Signature management — Sign and verify commits +
+
ostree-bootconfig-parser
@@ -68,6 +71,6 @@ +
Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/ostree-Core-repository-independent-functions.html b/apidoc/html/ostree-Core-repository-independent-functions.html index b3468b8b..f56228a6 100644 --- a/apidoc/html/ostree-Core-repository-independent-functions.html +++ b/apidoc/html/ostree-Core-repository-independent-functions.html @@ -8,7 +8,7 @@ - + @@ -35,8 +35,8 @@

Functions

--++ @@ -472,8 +472,8 @@

Types and Values

--++ @@ -2382,6 +2382,26 @@ if none

ostree_commit_get_timestamp ()

guint64
 ostree_commit_get_timestamp (GVariant *commit_variant);
+
+

Parameters

+
+++++ + + + + + +

commit_variant

Commit object

 
+ +
+

Returns

+

timestamp in seconds since the Unix epoch, UTC

+
+

Since: 2016.3


@@ -2850,6 +2870,6 @@ entry corresponds to an object in the associated commit.

+
Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/ostree-GPG-signature-verification-results.html b/apidoc/html/ostree-GPG-signature-verification-results.html index a5c8b33c..9cd9c4cc 100644 --- a/apidoc/html/ostree-GPG-signature-verification-results.html +++ b/apidoc/html/ostree-GPG-signature-verification-results.html @@ -7,8 +7,8 @@ - - + + @@ -20,7 +20,7 @@ Home Up Prev -Next +Next
@@ -35,8 +35,8 @@

Functions

--++ @@ -110,8 +110,8 @@

Types and Values

--++ @@ -564,7 +564,7 @@ These may be returned by any API which creates or verifies signatures.

@@ -572,7 +572,7 @@ These may be returned by any API which creates or verifies signatures.

@@ -605,116 +605,116 @@ The attribute's GVariantType is shown in brackets.

@@ -739,7 +739,7 @@ for future variations.

@@ -749,6 +749,6 @@ for future variations.

+
Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/ostree-In-memory-modifiable-filesystem-tree.html b/apidoc/html/ostree-In-memory-modifiable-filesystem-tree.html index e3387de8..1f109bbb 100644 --- a/apidoc/html/ostree-In-memory-modifiable-filesystem-tree.html +++ b/apidoc/html/ostree-In-memory-modifiable-filesystem-tree.html @@ -8,7 +8,7 @@ - + @@ -35,8 +35,8 @@

Functions

OSTREE_GPG_ERROR_EXPIRED_KEY

A signature was found, but the key used to - sign it has expired. Since: 2020.1.

+sign it has expired. Since: 2020.1.

 

OSTREE_GPG_ERROR_REVOKED_KEY

A signature was found, but the key used to - sign it has been revoked. Since: 2020.1.

+sign it has been revoked. Since: 2020.1.

 

OSTREE_GPG_SIGNATURE_ATTR_VALID

-

[G_VARIANT_TYPE_BOOLEAN] Is the signature valid?

+

[G_VARIANT_TYPE_BOOLEAN] Is the signature valid?

 

OSTREE_GPG_SIGNATURE_ATTR_SIG_EXPIRED

-

[G_VARIANT_TYPE_BOOLEAN] Has the signature expired?

+

[G_VARIANT_TYPE_BOOLEAN] Has the signature expired?

 

OSTREE_GPG_SIGNATURE_ATTR_KEY_EXPIRED

-

[G_VARIANT_TYPE_BOOLEAN] Has the signing key expired?

+

[G_VARIANT_TYPE_BOOLEAN] Has the signing key expired?

 

OSTREE_GPG_SIGNATURE_ATTR_KEY_REVOKED

-

[G_VARIANT_TYPE_BOOLEAN] Has the signing key been revoked?

+

[G_VARIANT_TYPE_BOOLEAN] Has the signing key been revoked?

 

OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING

-

[G_VARIANT_TYPE_BOOLEAN] Is the signing key missing?

+

[G_VARIANT_TYPE_BOOLEAN] Is the signing key missing?

 

OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT

-

[G_VARIANT_TYPE_STRING] Fingerprint of the signing key

+

[G_VARIANT_TYPE_STRING] Fingerprint of the signing key

 

OSTREE_GPG_SIGNATURE_ATTR_TIMESTAMP

-

[G_VARIANT_TYPE_INT64] Signature creation Unix timestamp

+

[G_VARIANT_TYPE_INT64] Signature creation Unix timestamp

 

OSTREE_GPG_SIGNATURE_ATTR_EXP_TIMESTAMP

-

[G_VARIANT_TYPE_INT64] Signature expiration Unix timestamp (0 if no - expiration)

+

[G_VARIANT_TYPE_INT64] Signature expiration Unix timestamp (0 if no +expiration)

 

OSTREE_GPG_SIGNATURE_ATTR_PUBKEY_ALGO_NAME

-

[G_VARIANT_TYPE_STRING] Name of the public key algorithm used to create - the signature

+

[G_VARIANT_TYPE_STRING] Name of the public key algorithm used to create +the signature

 

OSTREE_GPG_SIGNATURE_ATTR_HASH_ALGO_NAME

-

[G_VARIANT_TYPE_STRING] Name of the hash algorithm used to create the - signature

+

[G_VARIANT_TYPE_STRING] Name of the hash algorithm used to create the +signature

 

OSTREE_GPG_SIGNATURE_ATTR_USER_NAME

-

[G_VARIANT_TYPE_STRING] The name of the signing key's primary user

+

[G_VARIANT_TYPE_STRING] The name of the signing key's primary user

 

OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL

-

[G_VARIANT_TYPE_STRING] The email address of the signing key's primary - user

+

[G_VARIANT_TYPE_STRING] The email address of the signing key's primary +user

 

OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY

-

[G_VARIANT_TYPE_STRING] Fingerprint of the signing key's primary key - (will be the same as OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT if the - the signature is already from the primary key rather than a subkey, - and will be the empty string if the key is missing.)

+

[G_VARIANT_TYPE_STRING] Fingerprint of the signing key's primary key +(will be the same as OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT if the +the signature is already from the primary key rather than a subkey, +and will be the empty string if the key is missing.)

 

OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP

-

[G_VARIANT_TYPE_INT64] Key expiration Unix timestamp (0 if no - expiration or if the key is missing)

+

[G_VARIANT_TYPE_INT64] Key expiration Unix timestamp (0 if no +expiration or if the key is missing)

 

OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP_PRIMARY

-

[G_VARIANT_TYPE_INT64] Key expiration Unix timestamp of the signing key's - primary key (will be the same as OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP - if the signing key is the primary key and 0 if no expiration or if the key - is missing)

+

[G_VARIANT_TYPE_INT64] Key expiration Unix timestamp of the signing key's +primary key (will be the same as OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP +if the signing key is the primary key and 0 if no expiration or if the key +is missing)

 

OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT

-

Use the default output format

+

Use the default output format

 
--++ @@ -172,8 +172,8 @@

Types and Values

--++ @@ -622,6 +622,6 @@ the contents will be loaded only when needed.

+
Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/ostree-OstreeRepo.html b/apidoc/html/ostree-OstreeRepo.html index 91b9bc83..c9a27839 100644 --- a/apidoc/html/ostree-OstreeRepo.html +++ b/apidoc/html/ostree-OstreeRepo.html @@ -8,7 +8,7 @@ - + @@ -35,8 +35,8 @@

Functions

typedef
--++ @@ -695,6 +695,14 @@ + + + + @@ -8352,7 +8406,7 @@ by

OSTREE_REPO_COMMIT_STATE_PARTIAL

@@ -8360,7 +8414,7 @@ by

OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL

@@ -8816,6 +8870,6 @@ as - List of pack file checksums in which this object appears

+
Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/ostree-Progress-notification-system-for-asynchronous-operations.html b/apidoc/html/ostree-Progress-notification-system-for-asynchronous-operations.html index cb63dde3..398043d0 100644 --- a/apidoc/html/ostree-Progress-notification-system-for-asynchronous-operations.html +++ b/apidoc/html/ostree-Progress-notification-system-for-asynchronous-operations.html @@ -8,7 +8,7 @@ - + @@ -35,8 +35,8 @@

Functions

+gboolean + +ostree_repo_commit_modifier_set_sepolicy_from_commit () +
void @@ -1156,8 +1164,8 @@

Types and Values

--++ @@ -5232,6 +5240,48 @@ policy wins.


+

ostree_repo_commit_modifier_set_sepolicy_from_commit ()

+
gboolean
+ostree_repo_commit_modifier_set_sepolicy_from_commit
+                               (OstreeRepoCommitModifier *modifier,
+                                OstreeRepo *repo,
+                                const char *rev,
+                                GCancellable *cancellable,
+                                GError **error);
+

In many cases, one wants to create a "derived" commit from base commit. +SELinux policy labels are part of that base commit. This API allows +one to easily set up SELinux labeling from a base commit.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

modifier

Commit modifier

 

repo

OSTree repo containing rev +

 

rev

Find SELinux policy from this base commit

 
+ + +
+

ostree_repo_commit_modifier_set_devino_cache ()

void
 ostree_repo_commit_modifier_set_devino_cache
@@ -7415,11 +7465,15 @@ string to pull the latest commit for that ref

  • override-remote-name (s): If local, add this remote to refspec

  • gpg-verify (b): GPG verify commits

  • gpg-verify-summary (b): GPG verify summary

  • +
  • disable-sign-verify (b): Disable signapi verification of commits

  • +
  • disable-sign-verify-summary (b): Disable signapi verification of the summary

  • depth (i): How far in the history to traverse; default is 0, -1 means infinite

  • +
  • per-object-fsync (b): Perform disk writes more slowly, avoiding a single large I/O sync

  • disable-static-deltas (b): Do not use static deltas

  • require-static-deltas (b): Require static deltas

  • override-commit-ids (as): Array of specific commit IDs to fetch for refs

  • timestamp-check (b): Verify commit timestamps are newer than current (when pulling via ref); Since: 2017.11

  • +
  • timestamp-check-from-rev (s): Verify that all fetched commit timestamps are newer than timestamp of given rev; Since: 2020.4

  • metadata-size-restriction (t): Restrict metadata objects to a maximum number of bytes; 0 to disable. Since: 2018.9

  • dry-run (b): Only print information on what will be downloaded (requires static deltas)

  • override-url (s): Fetch objects from this URL if remote specifies no metalink in options

  • @@ -8344,7 +8398,7 @@ by

    OSTREE_REPO_COMMIT_STATE_NORMAL

    Commit is complete. This is the default. - (Since: 2017.14.)

    +(Since: 2017.14.)

     

    One or more objects are missing from the - local copy of the commit, but metadata is present. (Since: 2015.7.)

    +local copy of the commit, but metadata is present. (Since: 2015.7.)

     

    One or more objects are missing from the - local copy of the commit, due to an fsck --delete. (Since: 2019.4.)

    +local copy of the commit, due to an fsck --delete. (Since: 2019.4.)

     
    --++ @@ -158,8 +158,8 @@

    Types and Values

    --++ @@ -298,17 +298,17 @@ function returns.

    9 10 11 - +ostree_async_progress_get(progress, + "outstanding-fetches","u",&outstanding_fetches, + "bytes-received","t",&bytes_received, + "status","s",&status, + "refs","@a{ss}",&refs_variant, + NULL);
    typedef
    guint32 outstanding_fetches;
    -guint64 bytes_received;
    -g_autofree gchar *status = NULL;
    -g_autoptr(GVariant) refs_variant = NULL;
    +        
    guint32 outstanding_fetches;
    +guint64 bytes_received;
    +g_autofree gchar *status = NULL;
    +g_autoptr(GVariant) refs_variant = NULL;
     
    -ostree_async_progress_get (progress,
    -                           "outstanding-fetches", "u", &outstanding_fetches,
    -                           "bytes-received", "t", &bytes_received,
    -                           "status", "s", &status,
    -                           "refs", "@a{ss}", &refs_variant,
    -                           NULL);
    @@ -452,15 +452,15 @@ parameters, so they may be floating.

    7 8 9 -
    guint32 outstanding_fetches = 15;
    -guint64 bytes_received = 1000;
    +        
    guint32 outstanding_fetches = 15;
    +guint64 bytes_received = 1000;
     
    -ostree_async_progress_set (progress,
    -                           "outstanding-fetches", "u", outstanding_fetches,
    -                           "bytes-received", "t", bytes_received,
    -                           "status", "s", "Updated status",
    -                           "refs", "@a{ss}", g_variant_new_parsed ("@a{ss} {}"),
    -                           NULL);
    +ostree_async_progress_set (progress, + "outstanding-fetches", "u", outstanding_fetches, + "bytes-received", "t", bytes_received, + "status", "s", "Updated status", + "refs", "@a{ss}", g_variant_new_parsed ("@a{ss} {}"), + NULL);
    @@ -589,6 +589,6 @@ events will be queued.

    +
    Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/ostree-Root-partition-mount-point.html b/apidoc/html/ostree-Root-partition-mount-point.html index cf860858..3b1b1062 100644 --- a/apidoc/html/ostree-Root-partition-mount-point.html +++ b/apidoc/html/ostree-Root-partition-mount-point.html @@ -8,7 +8,7 @@ - + @@ -35,8 +35,8 @@

    Functions

    --++ @@ -390,8 +390,8 @@

    Types and Values

    --++ @@ -2125,6 +2125,6 @@ later, instead.

    +
    Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/ostree-SELinux-policy-management.html b/apidoc/html/ostree-SELinux-policy-management.html index fe61c781..1fa9eaed 100644 --- a/apidoc/html/ostree-SELinux-policy-management.html +++ b/apidoc/html/ostree-SELinux-policy-management.html @@ -8,7 +8,7 @@ - + @@ -35,8 +35,8 @@

    Functions

    --++ @@ -116,8 +116,8 @@

    Types and Values

    --++ @@ -486,6 +486,6 @@ ostree_sepolicy_fscreatecon_cleanup ( -
    Generated by GTK-Doc V1.29 +
    Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/ostree-Signature-management.html b/apidoc/html/ostree-Signature-management.html new file mode 100644 index 00000000..dcd6075a --- /dev/null +++ b/apidoc/html/ostree-Signature-management.html @@ -0,0 +1,865 @@ + + + + +Signature management: OSTree API references + + + + + + + + + +
    + + + + + + +
    +
    +
    + + +
    +

    Signature management

    +

    Signature management — Sign and verify commits

    +
    +
    +

    Functions

    +
    ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +GPtrArray * + +ostree_sign_get_all () +
    +gboolean + +ostree_sign_commit () +
    +gboolean + +ostree_sign_commit_verify () +
    +gboolean + +ostree_sign_data () +
    +gboolean + +ostree_sign_data_verify () +
    +OstreeSign * + +ostree_sign_get_by_name () +
    const gchar * + +ostree_sign_get_name () +
    +gboolean + +ostree_sign_add_pk () +
    +gboolean + +ostree_sign_clear_keys () +
    +gboolean + +ostree_sign_load_pk () +
    const gchar * + +ostree_sign_metadata_format () +
    const gchar * + +ostree_sign_metadata_key () +
    +gboolean + +ostree_sign_set_pk () +
    +gboolean + +ostree_sign_set_sk () +
    +gboolean + +ostree_sign_summary () +
    +
    +
    +

    Types and Values

    +
    ++++ + + + + +
     OstreeSign
    +
    +
    +

    Description

    +

    An OstreeSign interface allows to select and use any available engine +for signing or verifying the commit object or summary file.

    +
    +
    +

    Functions

    +
    +

    ostree_sign_get_all ()

    +
    GPtrArray *
    +ostree_sign_get_all (void);
    +

    Return an array with newly allocated instances of all available +signing engines; they will not be initialized.

    +
    +

    Returns

    +

    an array of signing engines.

    +

    [transfer full][element-type OstreeSign]

    +
    +

    Since: 2020.2

    +
    +
    +
    +

    ostree_sign_commit ()

    +
    gboolean
    +ostree_sign_commit (OstreeSign *self,
    +                    OstreeRepo *repo,
    +                    const gchar *commit_checksum,
    +                    GCancellable *cancellable,
    +                    GError **error);
    +

    Add a signature to a commit.

    +

    Depending of the signing engine used you will need to load +the secret key with ostree_sign_set_sk.

    +
    +

    Parameters

    +
    +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    self

    an OstreeSign object

     

    repo

    an OsreeRepo object

     

    commit_checksum

    SHA256 of given commit to sign

     

    cancellable

    A GCancellable

     

    error

    a GError

     
    +
    +
    +

    Returns

    +

    TRUE +if commit has been signed successfully, +FALSE +in case of error (error +will contain the reason).

    +
    +

    Since: 2020.2

    +
    +
    +
    +

    ostree_sign_commit_verify ()

    +
    gboolean
    +ostree_sign_commit_verify (OstreeSign *self,
    +                           OstreeRepo *repo,
    +                           const gchar *commit_checksum,
    +                           char **out_success_message,
    +                           GCancellable *cancellable,
    +                           GError **error);
    +

    Verify if commit is signed with known key.

    +

    Depending of the signing engine used you will need to load +the public key(s) for verification with ostree_sign_set_pk, +ostree_sign_add_pk and/or ostree_sign_load_pk.

    +
    +

    Parameters

    +
    +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    self

    an OstreeSign object

     

    repo

    an OsreeRepo object

     

    commit_checksum

    SHA256 of given commit to verify

     

    cancellable

    A GCancellable

     

    error

    a GError

     
    +
    +
    +

    Returns

    +

    TRUE +if commit has been verified successfully, +FALSE +in case of error or no valid keys are available (error +will contain the reason).

    +
    +

    Since: 2020.2

    +
    +
    +
    +

    ostree_sign_data ()

    +
    gboolean
    +ostree_sign_data (OstreeSign *self,
    +                  GBytes *data,
    +                  GBytes **signature,
    +                  GCancellable *cancellable,
    +                  GError **error);
    +

    Sign the given data + with pre-loaded secret key.

    +

    Depending of the signing engine used you will need to load +the secret key with ostree_sign_set_sk.

    +
    +

    Parameters

    +
    +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    self

    an OstreeSign object

     

    data

    the raw data to be signed with pre-loaded secret key

     

    signature

    in case of success will contain signature

     

    cancellable

    A GCancellable

     

    error

    a GError

     
    +
    +
    +

    Returns

    +

    TRUE +if data +has been signed successfully, +FALSE +in case of error (error +will contain the reason).

    +
    +

    Since: 2020.2

    +
    +
    +
    +

    ostree_sign_data_verify ()

    +
    gboolean
    +ostree_sign_data_verify (OstreeSign *self,
    +                         GBytes *data,
    +                         GVariant *signatures,
    +                         char **out_success_message,
    +                         GError **error);
    +

    Verify given data against signatures with pre-loaded public keys.

    +

    Depending of the signing engine used you will need to load +the public key(s) with ostree_sign_set_pk, ostree_sign_add_pk +or ostree_sign_load_pk.

    +
    +

    Parameters

    +
    +++++ + + + + + + + + + + + + + + + + + + + + + + +

    self

    an OstreeSign object

     

    data

    the raw data to check

     

    signatures

    the signatures to be checked

     

    error

    a GError

     
    +
    +
    +

    Returns

    +

    TRUE +if data +has been signed at least with any single valid key, +FALSE +in case of error or no valid keys are available (error +will contain the reason).

    +
    +

    Since: 2020.2

    +
    +
    +
    +

    ostree_sign_get_by_name ()

    +
    OstreeSign *
    +ostree_sign_get_by_name (const gchar *name,
    +                         GError **error);
    +

    Create a new instance of a signing engine.

    +
    +

    Parameters

    +
    +++++ + + + + + + + + + + + + +

    name

    the name of desired signature engine

     

    error

    return location for a GError

     
    +
    +
    +

    Returns

    +

    New signing engine, or NULL if the engine is not known.

    +

    [transfer full]

    +
    +

    Since: 2020.2

    +
    +
    +
    +

    ostree_sign_get_name ()

    +
    const gchar *
    +ostree_sign_get_name (OstreeSign *self);
    +

    Return the pointer to the name of currently used/selected signing engine.

    +
    +

    Parameters

    +
    +++++ + + + + + +

    self

    an OstreeSign object

     
    +
    +
    +

    Returns

    +

    pointer to the name +NULL +in case of error (unlikely).

    +

    [transfer none]

    +
    +

    Since: 2020.2

    +
    +
    +
    +

    ostree_sign_add_pk ()

    +
    gboolean
    +ostree_sign_add_pk (OstreeSign *self,
    +                    GVariant *public_key,
    +                    GError **error);
    +

    Add the public key for verification. Could be called multiple times for +adding all needed keys to be used for verification.

    +

    The public_key + argument depends of the particular engine implementation.

    +
    +

    Parameters

    +
    +++++ + + + + + + + + + + + + + + + + + +

    self

    an OstreeSign object

     

    public_key

    single public key to be added

     

    error

    a GError

     
    +
    +
    +

    Returns

    +

    TRUE +in case if the key could be added successfully, +FALSE +in case of error (error +will contain the reason).

    +
    +

    Since: 2020.2

    +
    +
    +
    +

    ostree_sign_clear_keys ()

    +
    gboolean
    +ostree_sign_clear_keys (OstreeSign *self,
    +                        GError **error);
    +

    Clear all previously preloaded secret and public keys.

    +
    +

    Parameters

    +
    +++++ + + + + + + + + + + + + +

    self

    an OstreeSign object

     

    error

    a GError

     
    +
    +
    +

    Returns

    +

    TRUE +in case if no errors, FALSE +in case of error

    +
    +

    Since: 2020.2

    +
    +
    +
    +

    ostree_sign_load_pk ()

    +
    gboolean
    +ostree_sign_load_pk (OstreeSign *self,
    +                     GVariant *options,
    +                     GError **error);
    +

    Load public keys for verification from anywhere. +It is expected that all keys would be added to already pre-loaded keys.

    +

    The options + argument depends of the particular engine implementation.

    +

    For example, ed25515 + engine could use following string-formatted options:

    +
      +
    • filename + -- single file to use to load keys from

    • +
    • basedir + -- directory containing subdirectories +'trusted.ed25519.d' and 'revoked.ed25519.d' with appropriate +public keys. Used for testing and re-definition of system-wide +directories if defaults are not suitable for any reason.

    • +
    +
    +

    Parameters

    +
    +++++ + + + + + + + + + + + + + + + + + +

    self

    an OstreeSign object

     

    options

    any options

     

    error

    a GError

     
    +
    +
    +

    Returns

    +

    TRUE +in case if at least one key could be load successfully, +FALSE +in case of error (error +will contain the reason).

    +
    +

    Since: 2020.2

    +
    +
    +
    +

    ostree_sign_metadata_format ()

    +
    const gchar *
    +ostree_sign_metadata_format (OstreeSign *self);
    +

    Return the pointer to the string with format used in (detached) metadata for +current signing engine.

    +
    +

    Parameters

    +
    +++++ + + + + + +

    self

    an OstreeSign object

     
    +
    +
    +

    Returns

    +

    pointer to the metadata format, +NULL +in case of error (unlikely).

    +

    [transfer none]

    +
    +

    Since: 2020.2

    +
    +
    +
    +

    ostree_sign_metadata_key ()

    +
    const gchar *
    +ostree_sign_metadata_key (OstreeSign *self);
    +

    Return the pointer to the name of the key used in (detached) metadata for +current signing engine.

    +
    +

    Parameters

    +
    +++++ + + + + + +

    self

    an OstreeSign object

     
    +
    +
    +

    Returns

    +

    pointer to the metadata key name, +NULL +in case of error (unlikely).

    +

    [transfer none]

    +
    +

    Since: 2020.2

    +
    +
    +
    +

    ostree_sign_set_pk ()

    +
    gboolean
    +ostree_sign_set_pk (OstreeSign *self,
    +                    GVariant *public_key,
    +                    GError **error);
    +

    Set the public key for verification. It is expected what all +previously pre-loaded public keys will be dropped.

    +

    The public_key + argument depends of the particular engine implementation.

    +
    +

    Parameters

    +
    +++++ + + + + + + + + + + + + + + + + + +

    self

    an OstreeSign object

     

    public_key

    single public key to be added

     

    error

    a GError

     
    +
    +
    +

    Returns

    +

    TRUE +in case if the key could be set successfully, +FALSE +in case of error (error +will contain the reason).

    +
    +

    Since: 2020.2

    +
    +
    +
    +

    ostree_sign_set_sk ()

    +
    gboolean
    +ostree_sign_set_sk (OstreeSign *self,
    +                    GVariant *secret_key,
    +                    GError **error);
    +

    Set the secret key to be used for signing data, commits and summary.

    +

    The secret_key + argument depends of the particular engine implementation.

    +
    +

    Parameters

    +
    +++++ + + + + + + + + + + + + + + + + + +

    self

    an OstreeSign object

     

    secret_key

    secret key to be added

     

    error

    a GError

     
    +
    +
    +

    Returns

    +

    TRUE +in case if the key could be set successfully, +FALSE +in case of error (error +will contain the reason).

    +
    +

    Since: 2020.2

    +
    +
    +
    +

    ostree_sign_summary ()

    +
    gboolean
    +ostree_sign_summary (OstreeSign *self,
    +                     OstreeRepo *repo,
    +                     GVariant *keys,
    +                     GCancellable *cancellable,
    +                     GError **error);
    +

    Add a signature to a summary file. +Based on ostree_repo_add_gpg_signature_summary implementation.

    +
    +

    Parameters

    +
    +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    self

    Self

     

    repo

    ostree repository

     

    keys

    keys -- GVariant containing keys as GVarints specific to signature type.

     

    cancellable

    A GCancellable

     

    error

    a GError

     
    +
    +
    +

    Returns

    +

    TRUE +if summary file has been signed with all provided keys

    +
    +
    +
    +
    +

    Types and Values

    +
    +

    OstreeSign

    +
    typedef struct _OstreeSign OstreeSign;
    +
    +
    +
    + + + \ No newline at end of file diff --git a/apidoc/html/ostree-Simple-upgrade-class.html b/apidoc/html/ostree-Simple-upgrade-class.html index 9ba7d2b9..3fb9312a 100644 --- a/apidoc/html/ostree-Simple-upgrade-class.html +++ b/apidoc/html/ostree-Simple-upgrade-class.html @@ -8,7 +8,7 @@ - + @@ -35,8 +35,8 @@

    Functions

    --++ @@ -134,8 +134,8 @@

    Types and Values

    --++ @@ -710,6 +710,6 @@ with /etc, and update the bootloader configuration.

    +
    Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/ostree-ostree-bootconfig-parser.html b/apidoc/html/ostree-ostree-bootconfig-parser.html index 0f6b8237..c9fdc372 100644 --- a/apidoc/html/ostree-ostree-bootconfig-parser.html +++ b/apidoc/html/ostree-ostree-bootconfig-parser.html @@ -6,9 +6,9 @@ - + - + @@ -19,7 +19,7 @@ - +
    Home UpPrevPrev Next
    @@ -35,8 +35,8 @@

    Functions

    --++ @@ -109,8 +109,8 @@

    Types and Values

    --++ @@ -256,6 +256,6 @@ ostree_bootconfig_parser_get ( -
    Generated by GTK-Doc V1.29 +
    Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/ostree-ostree-chain-input-stream.html b/apidoc/html/ostree-ostree-chain-input-stream.html index c2ae1da1..472cfb12 100644 --- a/apidoc/html/ostree-ostree-chain-input-stream.html +++ b/apidoc/html/ostree-ostree-chain-input-stream.html @@ -8,7 +8,7 @@ - + @@ -35,8 +35,8 @@

    Functions

     
    --++
    @@ -52,8 +52,8 @@

    Types and Values

    --++ @@ -84,6 +84,6 @@ ostree_chain_input_stream_new (GP +
    Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/ostree-ostree-checksum-input-stream.html b/apidoc/html/ostree-ostree-checksum-input-stream.html index b58c5bd2..df11c0e3 100644 --- a/apidoc/html/ostree-ostree-checksum-input-stream.html +++ b/apidoc/html/ostree-ostree-checksum-input-stream.html @@ -8,7 +8,7 @@ - + @@ -35,8 +35,8 @@

    Functions

    struct
    --++
    @@ -52,8 +52,8 @@

    Types and Values

    --++ @@ -85,6 +85,6 @@ ostree_checksum_input_stream_new ( +
    Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/ostree-ostree-deployment.html b/apidoc/html/ostree-ostree-deployment.html index 1d09aa04..bcac84d9 100644 --- a/apidoc/html/ostree-ostree-deployment.html +++ b/apidoc/html/ostree-ostree-deployment.html @@ -8,7 +8,7 @@ - + @@ -35,8 +35,8 @@

    Functions

    struct
    --++ @@ -218,8 +218,8 @@

    Types and Values

    --++ @@ -642,6 +642,6 @@ ostree_deployment_unlocked_state_to_string +
    Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/ostree-ostree-diff.html b/apidoc/html/ostree-ostree-diff.html index e29cc69b..eaddbd67 100644 --- a/apidoc/html/ostree-ostree-diff.html +++ b/apidoc/html/ostree-ostree-diff.html @@ -8,7 +8,7 @@ - + @@ -35,8 +35,8 @@

    Functions

     
    --++ @@ -86,8 +86,8 @@

    Types and Values

    --++ @@ -364,6 +364,6 @@ ostree_diff_print (GFile * +
    Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/ostree-ostree-repo-file.html b/apidoc/html/ostree-ostree-repo-file.html index 93939093..1205e086 100644 --- a/apidoc/html/ostree-ostree-repo-file.html +++ b/apidoc/html/ostree-ostree-repo-file.html @@ -7,7 +7,7 @@ - + @@ -34,8 +34,8 @@

    Functions

    --++ @@ -138,8 +138,8 @@

    Types and Values

    --++ @@ -357,6 +357,6 @@ ostree_repo_file_tree_query_child ( +
    Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/ostree.devhelp2 b/apidoc/html/ostree.devhelp2 index 3bb2f8ff..ad15fe03 100644 --- a/apidoc/html/ostree.devhelp2 +++ b/apidoc/html/ostree.devhelp2 @@ -10,6 +10,7 @@ + @@ -67,7 +68,7 @@ - + @@ -171,6 +172,7 @@ + @@ -362,6 +364,22 @@ + + + + + + + + + + + + + + + + diff --git a/apidoc/html/reference.html b/apidoc/html/reference.html index 72f6613d..272075de 100644 --- a/apidoc/html/reference.html +++ b/apidoc/html/reference.html @@ -8,7 +8,7 @@ - + @@ -48,6 +48,9 @@
    GPG signature verification results — Inspect detached GPG signatures
    +Signature management — Sign and verify commits +
    +
    ostree-bootconfig-parser
    @@ -947,6 +950,10 @@ OstreeRepoFinderResultv, typedef in ostree-repo-finder
    +ostree_repo_commit_modifier_set_sepolicy_from_commit, function in OstreeRepo +
    +
    +
    ostree_repo_commit_modifier_set_xattr_callback, function in OstreeRepo
    @@ -1632,6 +1639,70 @@ ostree_repo_transaction_set_collection_ref, function in ostree-misc-experimental
    +OstreeSign, struct in Signature management +
    +
    +
    +ostree_sign_add_pk, function in Signature management +
    +
    +
    +ostree_sign_clear_keys, function in Signature management +
    +
    +
    +ostree_sign_commit, function in Signature management +
    +
    +
    +ostree_sign_commit_verify, function in Signature management +
    +
    +
    +ostree_sign_data, function in Signature management +
    +
    +
    +ostree_sign_data_verify, function in Signature management +
    +
    +
    +ostree_sign_get_all, function in Signature management +
    +
    +
    +ostree_sign_get_by_name, function in Signature management +
    +
    +
    +ostree_sign_get_name, function in Signature management +
    +
    +
    +ostree_sign_load_pk, function in Signature management +
    +
    +
    +ostree_sign_metadata_format, function in Signature management +
    +
    +
    +ostree_sign_metadata_key, function in Signature management +
    +
    +
    +ostree_sign_set_pk, function in Signature management +
    +
    +
    +ostree_sign_set_sk, function in Signature management +
    +
    +
    +ostree_sign_summary, function in Signature management +
    +
    +
    OstreeStaticDeltaGenerateOpt, enum in OstreeRepo
    @@ -1953,6 +2024,6 @@ OSTREE_YEAR_VERSION, macro in ostree-version +
    Generated by GTK-Doc V1.32 \ No newline at end of file diff --git a/apidoc/html/style.css b/apidoc/html/style.css index 4be4ede1..b4a1493b 100644 --- a/apidoc/html/style.css +++ b/apidoc/html/style.css @@ -293,29 +293,11 @@ h2 .extralinks, h3 .extralinks font-weight: normal; } -acronym,abbr +acronym,abbr { border-bottom: 1px dotted gray; } -/* code listings */ - -.listing_code .programlisting .normal, -.listing_code .programlisting .normal a, -.listing_code .programlisting .number, -.listing_code .programlisting .cbracket, -.listing_code .programlisting .symbol { color: #555753; } -.listing_code .programlisting .comment, -.listing_code .programlisting .linenum { color: #babdb6; } /* tango: aluminium 3 */ -.listing_code .programlisting .function, -.listing_code .programlisting .function a, -.listing_code .programlisting .preproc { color: #204a87; } /* tango: sky blue 3 */ -.listing_code .programlisting .string { color: #ad7fa8; } /* tango: plum */ -.listing_code .programlisting .keyword, -.listing_code .programlisting .usertype, -.listing_code .programlisting .type, -.listing_code .programlisting .type a { color: #4e9a06; } /* tango: chameleon 3 */ - .listing_frame { /* tango:sky blue 1 */ border: solid 1px #729fcf; @@ -481,3 +463,71 @@ acronym,abbr } } +.hll { background-color: #ffffcc } +.c { color: #408080; font-style: italic } /* Comment */ +.err { border: 1px solid #FF0000 } /* Error */ +.k { color: #008000; font-weight: bold } /* Keyword */ +.o { color: #666666 } /* Operator */ +.ch { color: #408080; font-style: italic } /* Comment.Hashbang */ +.cm { color: #408080; font-style: italic } /* Comment.Multiline */ +.cp { color: #BC7A00 } /* Comment.Preproc */ +.cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */ +.c1 { color: #408080; font-style: italic } /* Comment.Single */ +.cs { color: #408080; font-style: italic } /* Comment.Special */ +.gd { color: #A00000 } /* Generic.Deleted */ +.ge { font-style: italic } /* Generic.Emph */ +.gr { color: #FF0000 } /* Generic.Error */ +.gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.gi { color: #00A000 } /* Generic.Inserted */ +.go { color: #888888 } /* Generic.Output */ +.gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.gs { font-weight: bold } /* Generic.Strong */ +.gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.gt { color: #0044DD } /* Generic.Traceback */ +.kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.kp { color: #008000 } /* Keyword.Pseudo */ +.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.kt { color: #B00040 } /* Keyword.Type */ +.m { color: #666666 } /* Literal.Number */ +.s { color: #BA2121 } /* Literal.String */ +.na { color: #7D9029 } /* Name.Attribute */ +.nb { color: #008000 } /* Name.Builtin */ +.nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.no { color: #880000 } /* Name.Constant */ +.nd { color: #AA22FF } /* Name.Decorator */ +.ni { color: #999999; font-weight: bold } /* Name.Entity */ +.ne { color: #D2413A; font-weight: bold } /* Name.Exception */ +.nf { color: #0000FF } /* Name.Function */ +.nl { color: #A0A000 } /* Name.Label */ +.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.nt { color: #008000; font-weight: bold } /* Name.Tag */ +.nv { color: #19177C } /* Name.Variable */ +.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.w { color: #bbbbbb } /* Text.Whitespace */ +.mb { color: #666666 } /* Literal.Number.Bin */ +.mf { color: #666666 } /* Literal.Number.Float */ +.mh { color: #666666 } /* Literal.Number.Hex */ +.mi { color: #666666 } /* Literal.Number.Integer */ +.mo { color: #666666 } /* Literal.Number.Oct */ +.sa { color: #BA2121 } /* Literal.String.Affix */ +.sb { color: #BA2121 } /* Literal.String.Backtick */ +.sc { color: #BA2121 } /* Literal.String.Char */ +.dl { color: #BA2121 } /* Literal.String.Delimiter */ +.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.s2 { color: #BA2121 } /* Literal.String.Double */ +.se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ +.sh { color: #BA2121 } /* Literal.String.Heredoc */ +.si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ +.sx { color: #008000 } /* Literal.String.Other */ +.sr { color: #BB6688 } /* Literal.String.Regex */ +.s1 { color: #BA2121 } /* Literal.String.Single */ +.ss { color: #19177C } /* Literal.String.Symbol */ +.bp { color: #008000 } /* Name.Builtin.Pseudo */ +.fm { color: #0000FF } /* Name.Function.Magic */ +.vc { color: #19177C } /* Name.Variable.Class */ +.vg { color: #19177C } /* Name.Variable.Global */ +.vi { color: #19177C } /* Name.Variable.Instance */ +.vm { color: #19177C } /* Name.Variable.Magic */ +.il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/apidoc/ostree-docs.xml b/apidoc/ostree-docs.xml index 8721ffa8..1ad0de37 100644 --- a/apidoc/ostree-docs.xml +++ b/apidoc/ostree-docs.xml @@ -21,6 +21,7 @@ + diff --git a/apidoc/ostree-sections.txt b/apidoc/ostree-sections.txt index 32cf5228..979c8e93 100644 --- a/apidoc/ostree-sections.txt +++ b/apidoc/ostree-sections.txt @@ -379,6 +379,7 @@ ostree_repo_commit_modifier_new OstreeRepoCommitModifierXattrCallback ostree_repo_commit_modifier_set_xattr_callback ostree_repo_commit_modifier_set_sepolicy +ostree_repo_commit_modifier_set_sepolicy_from_commit ostree_repo_commit_modifier_set_devino_cache ostree_repo_commit_modifier_ref ostree_repo_commit_modifier_unref @@ -704,3 +705,25 @@ ostree_kernel_args_from_string ostree_kernel_args_to_strv ostree_kernel_args_to_string + +
    +ostree-sign +OstreeSign +ostree_sign_get_all +ostree_sign_commit +ostree_sign_commit_verify +ostree_sign_data +ostree_sign_data_verify +ostree_sign_get_by_name +ostree_sign_get_name +ostree_sign_add_pk +ostree_sign_clear_keys +ostree_sign_load_pk +ostree_sign_metadata_format +ostree_sign_metadata_key +ostree_sign_set_pk +ostree_sign_set_sk +ostree_sign_summary + +ostree_sign_get_type +
    diff --git a/apidoc/ostree.types b/apidoc/ostree.types index aa2b9f0b..d9a4dbf4 100644 --- a/apidoc/ostree.types +++ b/apidoc/ostree.types @@ -22,6 +22,7 @@ ostree_repo_finder_result_get_type ostree_repo_get_type ostree_repo_transaction_stats_get_type ostree_sepolicy_get_type +ostree_sign_get_type ostree_sysroot_get_type ostree_sysroot_upgrader_flags_get_type ostree_sysroot_upgrader_get_type diff --git a/apidoc/version.xml b/apidoc/version.xml index 8d52ac12..a771cf07 100644 --- a/apidoc/version.xml +++ b/apidoc/version.xml @@ -1 +1 @@ -2020.3 \ No newline at end of file +2020.4 \ No newline at end of file diff --git a/bash/ostree b/bash/ostree index 4aec588b..7256e40a 100644 --- a/bash/ostree +++ b/bash/ostree @@ -1484,6 +1484,48 @@ _ostree_show() { return 0 } +_ostree_sign() { + local boolean_options=" + $main_boolean_options + --delete -d + --verify -v + " + + local options_with_args=" + --sign-type + --keys-file + --keys-dir + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --keys-file|--keys-dir|--repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_commits + fi + esac + + return 0 +} + _ostree_static_delta_apply_offline() { local boolean_options=" $main_boolean_options @@ -1747,6 +1789,7 @@ _ostree() { reset rev-parse show + sign static-delta summary " diff --git a/buildutil/libglnx.m4 b/buildutil/libglnx.m4 index 5922805b..5a72e98b 100644 --- a/buildutil/libglnx.m4 +++ b/buildutil/libglnx.m4 @@ -25,10 +25,10 @@ AS_IF([test $enable_otmpfile = yes], [], [ AC_ARG_ENABLE(wrpseudo-compat, [AS_HELP_STRING([--enable-wrpseudo-compat], - [Disable use syscall() and filesystem calls to for compatibility with wrpseudo [default=no]])],, + [Disable use of syscall() in some cases for compatibility with pseudo [default=no]])],, [enable_wrpseudo_compat=no]) AS_IF([test $enable_wrpseudo_compat = no], [], [ - AC_DEFINE([ENABLE_WRPSEUDO_COMPAT], 1, [Define if we should be compatible with wrpseudo])]) + AC_DEFINE([ENABLE_WRPSEUDO_COMPAT], 1, [Define if we should be compatible with pseudo])]) dnl end LIBGLNX_CONFIGURE ]) diff --git a/config.h.in b/config.h.in index ac9b3713..44d3a44c 100644 --- a/config.h.in +++ b/config.h.in @@ -21,7 +21,7 @@ /* Define if we should avoid using O_TMPFILE */ #undef DISABLE_OTMPFILE -/* Define if we should be compatible with wrpseudo */ +/* Define if we should be compatible with pseudo */ #undef ENABLE_WRPSEUDO_COMPAT /* The system grub2-mkconfig executable name */ @@ -73,6 +73,9 @@ /* Define if we have libmount.pc */ #undef HAVE_LIBMOUNT +/* Define if using libsodium */ +#undef HAVE_LIBSODIUM + /* Define if we have libsoup.pc */ #undef HAVE_LIBSOUP diff --git a/configure b/configure index 4e903470..127efaac 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for libostree 2020.3. +# Generated by GNU Autoconf 2.69 for libostree 2020.4. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='libostree' PACKAGE_TARNAME='libostree' -PACKAGE_VERSION='2020.3' -PACKAGE_STRING='libostree 2020.3' +PACKAGE_VERSION='2020.4' +PACKAGE_STRING='libostree 2020.4' PACKAGE_BUGREPORT='walters@verbum.org' PACKAGE_URL='' @@ -719,6 +719,10 @@ GTKDOC_MKPDF GTKDOC_REBASE GTKDOC_CHECK_PATH GTKDOC_CHECK +USE_LIBSODIUM_FALSE +USE_LIBSODIUM_TRUE +OT_DEP_LIBSODIUM_LIBS +OT_DEP_LIBSODIUM_CFLAGS USE_GPGME_FALSE USE_GPGME_TRUE GPG_ERROR_CONFIG @@ -741,6 +745,8 @@ INTROSPECTION_GIRDIR INTROSPECTION_GENERATE INTROSPECTION_COMPILER INTROSPECTION_SCANNER +_GI_EXP_LIBDIR +_GI_EXP_DATADIR USE_CURL_OR_SOUP_FALSE USE_CURL_OR_SOUP_TRUE HAVE_LIBSOUP_CLIENT_CERTS_FALSE @@ -933,6 +939,7 @@ enable_trivial_httpd_cmdline enable_introspection with_gpgme with_gpgme_prefix +with_ed25519_libsodium with_html_dir enable_gtk_doc enable_gtk_doc_html @@ -996,6 +1003,8 @@ OT_DEP_GPGME_CFLAGS OT_DEP_GPGME_LIBS OT_DEP_GPG_ERROR_CFLAGS OT_DEP_GPG_ERROR_LIBS +OT_DEP_LIBSODIUM_CFLAGS +OT_DEP_LIBSODIUM_LIBS GTKDOC_DEPS_CFLAGS GTKDOC_DEPS_LIBS OT_DEP_LIBARCHIVE_CFLAGS @@ -1552,7 +1561,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures libostree 2020.3 to adapt to many kinds of systems. +\`configure' configures libostree 2020.4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1622,7 +1631,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of libostree 2020.3:";; + short | recursive ) echo "Configuration of libostree 2020.4:";; esac cat <<\_ACEOF @@ -1651,8 +1660,8 @@ Optional Features: Enable always building tests during 'make all' --disable-otmpfile Disable use of O_TMPFILE [default=no] --enable-wrpseudo-compat - Disable use syscall() and filesystem calls to for - compatibility with wrpseudo [default=no] + Disable use of syscall() in some cases for + compatibility with pseudo [default=no] --disable-glibtest do not try to compile and run a test GLIB program --disable-http2 Disable use of http2 (default: no) --enable-libsoup-client-certs @@ -1690,6 +1699,8 @@ Optional Packages: --with-soup Use libsoup [default=yes] --with-gpgme Use gpgme [default=yes] --with-gpgme-prefix=PFX prefix where GPGME is installed (optional) + --with-ed25519-libsodium + Use libsodium for ed25519 [default=no] --with-html-dir=PATH path to installed docs --without-libarchive Do not use libarchive --without-selinux Do not use SELinux @@ -1782,6 +1793,10 @@ Some influential environment variables: C compiler flags for OT_DEP_GPG_ERROR, overriding pkg-config OT_DEP_GPG_ERROR_LIBS linker flags for OT_DEP_GPG_ERROR, overriding pkg-config + OT_DEP_LIBSODIUM_CFLAGS + C compiler flags for OT_DEP_LIBSODIUM, overriding pkg-config + OT_DEP_LIBSODIUM_LIBS + linker flags for OT_DEP_LIBSODIUM, overriding pkg-config GTKDOC_DEPS_CFLAGS C compiler flags for GTKDOC_DEPS, overriding pkg-config GTKDOC_DEPS_LIBS @@ -1881,7 +1896,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -libostree configure 2020.3 +libostree configure 2020.4 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2353,7 +2368,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by libostree $as_me 2020.3, which was +It was created by libostree $as_me 2020.4, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3221,7 +3236,7 @@ fi # Define the identity of the package. PACKAGE='libostree' - VERSION='2020.3' + VERSION='2020.4' # Some tools Automake needs. @@ -5955,9 +5970,9 @@ test -n "$YACC" || YACC="yacc" YEAR_VERSION=2020 -RELEASE_VERSION=3 +RELEASE_VERSION=4 -PACKAGE_VERSION=2020.3 +PACKAGE_VERSION=2020.4 if echo "$CFLAGS" | grep -q -E -e '-Werror($| )'; then : @@ -15477,20 +15492,77 @@ esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $found_introspection" >&5 $as_echo "$found_introspection" >&6; } + + EXP_VAR=_GI_EXP_DATADIR + FROM_VAR="$datadir" + + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + full_var=$new_full_var + _GI_EXP_DATADIR="$full_var" + + + prefix=$prefix_save + exec_prefix=$exec_prefix_save + + + EXP_VAR=_GI_EXP_LIBDIR + FROM_VAR="$libdir" + + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + full_var=$new_full_var + _GI_EXP_LIBDIR="$full_var" + + + prefix=$prefix_save + exec_prefix=$exec_prefix_save + + INTROSPECTION_SCANNER= INTROSPECTION_COMPILER= INTROSPECTION_GENERATE= INTROSPECTION_GIRDIR= INTROSPECTION_TYPELIBDIR= if test "x$found_introspection" = "xyes"; then - INTROSPECTION_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0` - INTROSPECTION_COMPILER=`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0` - INTROSPECTION_GENERATE=`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0` - INTROSPECTION_GIRDIR=`$PKG_CONFIG --variable=girdir gobject-introspection-1.0` - INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)" + INTROSPECTION_SCANNER=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0` + INTROSPECTION_COMPILER=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0` + INTROSPECTION_GENERATE=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0` + INTROSPECTION_GIRDIR=`$PKG_CONFIG --define-variable=datadir="${_GI_EXP_DATADIR}" --variable=girdir gobject-introspection-1.0` + INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --define-variable=libdir="${_GI_EXP_LIBDIR}" --variable=typelibdir gobject-introspection-1.0)" INTROSPECTION_CFLAGS=`$PKG_CONFIG --cflags gobject-introspection-1.0` INTROSPECTION_LIBS=`$PKG_CONFIG --libs gobject-introspection-1.0` - INTROSPECTION_MAKEFILE=`$PKG_CONFIG --variable=datadir gobject-introspection-1.0`/gobject-introspection-1.0/Makefile.introspection + INTROSPECTION_MAKEFILE=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=datadir gobject-introspection-1.0`/gobject-introspection-1.0/Makefile.introspection fi @@ -16076,6 +16148,111 @@ else fi + +LIBSODIUM_DEPENDENCY="1.0.14" + +# Check whether --with-ed25519_libsodium was given. +if test "${with_ed25519_libsodium+set}" = set; then : + withval=$with_ed25519_libsodium; +else + with_ed25519_libsodium=no +fi + +if test x$with_ed25519_libsodium != xno; then : + + +$as_echo "#define HAVE_LIBSODIUM 1" >>confdefs.h + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_LIBSODIUM" >&5 +$as_echo_n "checking for OT_DEP_LIBSODIUM... " >&6; } + +if test -n "$OT_DEP_LIBSODIUM_CFLAGS"; then + pkg_cv_OT_DEP_LIBSODIUM_CFLAGS="$OT_DEP_LIBSODIUM_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsodium >= \$LIBSODIUM_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libsodium >= $LIBSODIUM_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_LIBSODIUM_CFLAGS=`$PKG_CONFIG --cflags "libsodium >= $LIBSODIUM_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_LIBSODIUM_LIBS"; then + pkg_cv_OT_DEP_LIBSODIUM_LIBS="$OT_DEP_LIBSODIUM_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsodium >= \$LIBSODIUM_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libsodium >= $LIBSODIUM_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_LIBSODIUM_LIBS=`$PKG_CONFIG --libs "libsodium >= $LIBSODIUM_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_LIBSODIUM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsodium >= $LIBSODIUM_DEPENDENCY" 2>&1` + else + OT_DEP_LIBSODIUM_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsodium >= $LIBSODIUM_DEPENDENCY" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_LIBSODIUM_PKG_ERRORS" >&5 + + have_libsodium=no +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + have_libsodium=no +else + OT_DEP_LIBSODIUM_CFLAGS=$pkg_cv_OT_DEP_LIBSODIUM_CFLAGS + OT_DEP_LIBSODIUM_LIBS=$pkg_cv_OT_DEP_LIBSODIUM_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + have_libsodium=yes +fi + if test x$have_libsodium = xno ; then : + + as_fn_error $? "Need LIBSODIUM version $LIBSODIUM_DEPENDENCY or later" "$LINENO" 5 + +fi + OSTREE_FEATURES="$OSTREE_FEATURES sign-ed25519" + +else + with_ed25519_libsodium=no +fi + if test "x$have_libsodium" = xyes; then + USE_LIBSODIUM_TRUE= + USE_LIBSODIUM_FALSE='#' +else + USE_LIBSODIUM_TRUE='#' + USE_LIBSODIUM_FALSE= +fi + + LIBARCHIVE_DEPENDENCY="libarchive >= 2.8.0" # What's in RHEL7.2. FUSE_DEPENDENCY="fuse >= 2.9.2" @@ -18339,6 +18516,10 @@ if test -z "${USE_GPGME_TRUE}" && test -z "${USE_GPGME_FALSE}"; then as_fn_error $? "conditional \"USE_GPGME\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${USE_LIBSODIUM_TRUE}" && test -z "${USE_LIBSODIUM_FALSE}"; then + as_fn_error $? "conditional \"USE_LIBSODIUM\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${HAVE_GTK_DOC_TRUE}" && test -z "${HAVE_GTK_DOC_FALSE}"; then as_fn_error $? "conditional \"HAVE_GTK_DOC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -18844,7 +19025,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by libostree $as_me 2020.3, which was +This file was extended by libostree $as_me 2020.4, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -18910,7 +19091,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -libostree config.status 2020.3 +libostree config.status 2020.4 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -20616,6 +20797,7 @@ echo " cryptographic checksums: $with_crypto systemd: $with_libsystemd libmount: $with_libmount + libsodium (ed25519 signatures): $with_ed25519_libsodium libarchive (parse tar files directly): $with_libarchive static deltas: yes (always enabled now) O_TMPFILE: $enable_otmpfile diff --git a/configure.ac b/configure.ac index f8d7b2be..855528c0 100644 --- a/configure.ac +++ b/configure.ac @@ -2,12 +2,12 @@ AC_PREREQ([2.63]) dnl To do a release: follow the instructions to update libostree-released.sym from dnl libostree-devel.sym, update the checksum in test-symbols.sh, set is_release_build=yes dnl below. Then make another post-release commit to bump the version and set -dnl is_release_build=yes +dnl is_release_build=no. dnl Seed the release notes with `git-shortlog-with-prs ..`. Then use dnl `git-evtag` to create the tag and push it. Finally, create a GitHub release and attach dnl the tarball from `make dist`. m4_define([year_version], [2020]) -m4_define([release_version], [3]) +m4_define([release_version], [4]) m4_define([package_version], [year_version.release_version]) AC_INIT([libostree], [package_version], [walters@verbum.org]) is_release_build=yes @@ -242,6 +242,21 @@ dnl to link to it directly. ) AM_CONDITIONAL(USE_GPGME, test "x$have_gpgme" = xyes) + +LIBSODIUM_DEPENDENCY="1.0.14" +AC_ARG_WITH(ed25519_libsodium, + AS_HELP_STRING([--with-ed25519-libsodium], [Use libsodium for ed25519 @<:@default=no@:>@]), + [], [with_ed25519_libsodium=no]) +AS_IF([test x$with_ed25519_libsodium != xno], [ + AC_DEFINE([HAVE_LIBSODIUM], 1, [Define if using libsodium]) + PKG_CHECK_MODULES(OT_DEP_LIBSODIUM, libsodium >= $LIBSODIUM_DEPENDENCY, have_libsodium=yes, have_libsodium=no) + AS_IF([ test x$have_libsodium = xno ], [ + AC_MSG_ERROR([Need LIBSODIUM version $LIBSODIUM_DEPENDENCY or later]) + ]) + OSTREE_FEATURES="$OSTREE_FEATURES sign-ed25519" +], with_ed25519_libsodium=no ) +AM_CONDITIONAL(USE_LIBSODIUM, test "x$have_libsodium" = xyes) + LIBARCHIVE_DEPENDENCY="libarchive >= 2.8.0" # What's in RHEL7.2. FUSE_DEPENDENCY="fuse >= 2.9.2" @@ -626,6 +641,7 @@ echo " cryptographic checksums: $with_crypto systemd: $with_libsystemd libmount: $with_libmount + libsodium (ed25519 signatures): $with_ed25519_libsodium libarchive (parse tar files directly): $with_libarchive static deltas: yes (always enabled now) O_TMPFILE: $enable_otmpfile diff --git a/libglnx/README.md b/libglnx/README.md index 3be38d72..587e5d47 100644 --- a/libglnx/README.md +++ b/libglnx/README.md @@ -1,4 +1,4 @@ -libglnx is the successor to libgsystem: https://git.gnome.org/browse/libgsystem +libglnx is the successor to [libgsystem](https://gitlab.gnome.org/Archive/libgsystem). It is for modules which depend on both GLib and Linux, intended to be used as a git submodule. diff --git a/libglnx/glnx-backport-autocleanups.h b/libglnx/glnx-backport-autocleanups.h index b5f3475d..50f469f2 100644 --- a/libglnx/glnx-backport-autocleanups.h +++ b/libglnx/glnx-backport-autocleanups.h @@ -49,7 +49,9 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMainContext, g_main_context_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMainLoop, g_main_loop_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSource, g_source_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMappedFile, g_mapped_file_unref) +#if GLIB_CHECK_VERSION(2, 36, 0) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMarkupParseContext, g_markup_parse_context_unref) +#endif G_DEFINE_AUTOPTR_CLEANUP_FUNC(gchar, g_free) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GNode, g_node_destroy) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GOptionContext, g_option_context_free) @@ -75,11 +77,15 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariant, g_variant_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantBuilder, g_variant_builder_unref) G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GVariantBuilder, g_variant_builder_clear) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantIter, g_variant_iter_free) +#if GLIB_CHECK_VERSION(2, 40, 0) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantDict, g_variant_dict_unref) G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GVariantDict, g_variant_dict_clear) +#endif G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantType, g_variant_type_free) +#if GLIB_CHECK_VERSION(2, 40, 0) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSubprocess, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSubprocessLauncher, g_object_unref) +#endif /* Add GObject-based types as needed. */ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GAsyncResult, g_object_unref) @@ -101,7 +107,9 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMount, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GOutputStream, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSocket, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSocketAddress, g_object_unref) +#if GLIB_CHECK_VERSION(2, 36, 0) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTask, g_object_unref) +#endif G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTlsCertificate, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTlsDatabase, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTlsInteraction, g_object_unref) diff --git a/libglnx/glnx-backports.h b/libglnx/glnx-backports.h index cd853cca..6c39cf22 100644 --- a/libglnx/glnx-backports.h +++ b/libglnx/glnx-backports.h @@ -27,6 +27,26 @@ G_BEGIN_DECLS +#if !GLIB_CHECK_VERSION(2, 34, 0) +#define g_clear_pointer(pp, destroy) \ + G_STMT_START { \ + G_STATIC_ASSERT (sizeof *(pp) == sizeof (gpointer)); \ + /* Only one access, please; work around type aliasing */ \ + union { char *in; gpointer *out; } _pp; \ + gpointer _p; \ + /* This assignment is needed to avoid a gcc warning */ \ + GDestroyNotify _destroy = (GDestroyNotify) (destroy); \ + \ + _pp.in = (char *) (pp); \ + _p = *_pp.out; \ + if (_p) \ + { \ + *_pp.out = NULL; \ + _destroy (_p); \ + } \ + } G_STMT_END +#endif + #if !GLIB_CHECK_VERSION(2, 44, 0) #define g_strv_contains glnx_strv_contains @@ -43,4 +63,16 @@ gboolean glnx_set_object (GObject **object_ptr, #endif /* !GLIB_CHECK_VERSION(2, 44, 0) */ +#ifndef g_assert_nonnull +#define g_assert_nonnull(x) g_assert (x != NULL) +#endif + +#ifndef g_assert_null +#define g_assert_null(x) g_assert (x == NULL) +#endif + +#if !GLIB_CHECK_VERSION (2, 38, 0) +#define g_test_skip(s) g_test_message ("SKIP: %s", s) +#endif + G_END_DECLS diff --git a/libglnx/glnx-fdio.c b/libglnx/glnx-fdio.c index 12879cd7..e537a9bc 100644 --- a/libglnx/glnx-fdio.c +++ b/libglnx/glnx-fdio.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -825,7 +826,7 @@ glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes) have_cfr = 0; try_cfr = false; } - else if (errno == EXDEV) + else if (G_IN_SET (errno, EXDEV, EOPNOTSUPP)) /* We won't try cfr again for this run, but let's be * conservative and not mark it as available/unavailable until * we know for sure. @@ -938,7 +939,7 @@ glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes) gboolean glnx_file_copy_at (int src_dfd, const char *src_subpath, - struct stat *src_stbuf, + const struct stat *src_stbuf, int dest_dfd, const char *dest_subpath, GLnxFileCopyFlags copyflags, diff --git a/libglnx/glnx-fdio.h b/libglnx/glnx-fdio.h index 9c57dc5e..f95e473f 100644 --- a/libglnx/glnx-fdio.h +++ b/libglnx/glnx-fdio.h @@ -193,7 +193,7 @@ typedef enum { gboolean glnx_file_copy_at (int src_dfd, const char *src_subpath, - struct stat *src_stbuf, + const struct stat *src_stbuf, int dest_dfd, const char *dest_subpath, GLnxFileCopyFlags copyflags, diff --git a/libglnx/libglnx.m4 b/libglnx/libglnx.m4 index 5922805b..5a72e98b 100644 --- a/libglnx/libglnx.m4 +++ b/libglnx/libglnx.m4 @@ -25,10 +25,10 @@ AS_IF([test $enable_otmpfile = yes], [], [ AC_ARG_ENABLE(wrpseudo-compat, [AS_HELP_STRING([--enable-wrpseudo-compat], - [Disable use syscall() and filesystem calls to for compatibility with wrpseudo [default=no]])],, + [Disable use of syscall() in some cases for compatibility with pseudo [default=no]])],, [enable_wrpseudo_compat=no]) AS_IF([test $enable_wrpseudo_compat = no], [], [ - AC_DEFINE([ENABLE_WRPSEUDO_COMPAT], 1, [Define if we should be compatible with wrpseudo])]) + AC_DEFINE([ENABLE_WRPSEUDO_COMPAT], 1, [Define if we should be compatible with pseudo])]) dnl end LIBGLNX_CONFIGURE ]) diff --git a/libglnx/tests/libglnx-testlib.c b/libglnx/tests/libglnx-testlib.c index 5687d807..869d144d 100644 --- a/libglnx/tests/libglnx-testlib.c +++ b/libglnx/tests/libglnx-testlib.c @@ -23,6 +23,8 @@ #include +#include + #include "libglnx.h" struct _GLnxTestAutoTempDir @@ -63,4 +65,10 @@ _glnx_test_auto_temp_dir_leave (_GLnxTestAutoTempDir *dir) glnx_tmpdir_delete (&dir->temp_dir, NULL, &error); g_assert_no_error (error); + + g_close (dir->old_cwd_fd, &error); + g_assert_no_error (error); + + g_free (dir->old_cwd); + g_free (dir); } diff --git a/libglnx/tests/libglnx-testlib.h b/libglnx/tests/libglnx-testlib.h index 0d3a0751..d45ba860 100644 --- a/libglnx/tests/libglnx-testlib.h +++ b/libglnx/tests/libglnx-testlib.h @@ -45,4 +45,4 @@ void _glnx_test_auto_temp_dir_leave (_GLnxTestAutoTempDir *dir); G_DEFINE_AUTOPTR_CLEANUP_FUNC(_GLnxTestAutoTempDir, _glnx_test_auto_temp_dir_leave); #define _GLNX_TEST_SCOPED_TEMP_DIR \ - g_autoptr(_GLnxTestAutoTempDir) temp_dir = _glnx_test_auto_temp_dir_enter () + G_GNUC_UNUSED g_autoptr(_GLnxTestAutoTempDir) temp_dir = _glnx_test_auto_temp_dir_enter () diff --git a/libglnx/tests/test-libglnx-xattrs.c b/libglnx/tests/test-libglnx-xattrs.c index 63e12314..82def4aa 100644 --- a/libglnx/tests/test-libglnx-xattrs.c +++ b/libglnx/tests/test-libglnx-xattrs.c @@ -218,7 +218,11 @@ test_xattr_races (void) /* FIXME - this deadlocks for me on 4.9.4-201.fc25.x86_64, whether * using overlayfs or xfs as source/dest. */ +#if GLIB_CHECK_VERSION (2, 36, 0) const guint nprocs = MAX (4, g_get_num_processors ()); +#else + const guint nprocs = 4; +#endif struct XattrWorker wdata[nprocs]; GThread *threads[nprocs]; g_autoptr(GError) local_error = NULL; diff --git a/man/ostree-checkout.xml b/man/ostree-checkout.xml index 06385927..3956e34f 100644 --- a/man/ostree-checkout.xml +++ b/man/ostree-checkout.xml @@ -68,7 +68,7 @@ Boston, MA 02111-1307, USA. - , + , Do not change file ownership or initialize extended attributes. @@ -108,6 +108,14 @@ Boston, MA 02111-1307, USA. directories. Requires -H. + + + + + Process whiteout files (Docker style). + + + @@ -131,6 +139,69 @@ Boston, MA 02111-1307, USA. Process many checkouts from input file. + + + ="POLICY" + + + POLICY is a boolean which specifies whether fsync should be + used or not. Default to true. + + + + + , + + + + Do not fall back to full copies if hardlinking fails. + + + + + , + + + + Do not hardlink zero-sized files. + + + + + , + + + Never hardlink (but may reflink if available). + + + + + , + + + + Suppress mode bits outside of 0775 for directories (suid, + world writable, etc.). + + + + + ="FILE" + + + Skip checking out the absolute file paths listed in FILE, + one per line. + + + + + + + + Set SELinux labels based on policy in root filesystem PATH + (may be /). This implies --force-copy. + + diff --git a/man/ostree-commit.xml b/man/ostree-commit.xml index c64a7a00..b0c5b335 100644 --- a/man/ostree-commit.xml +++ b/man/ostree-commit.xml @@ -106,6 +106,15 @@ Boston, MA 02111-1307, USA. + + ="REV" + + + Start from the content in a commit. This differs from --tree=ref=REV in that no commit modifiers are applied. This is usually what you want when + creating a derived commit. This is also used for --selinux-policy-from-base. + + + ="KEY=VALUE" @@ -251,6 +260,39 @@ Boston, MA 02111-1307, USA. POLICY is a boolean which specifies whether fsync should be used or not. Default to true. + + + + + Use particular signature engine. Currently + available ed25519 and dummy + signature types. + + The default is ed25519. + + + + + ="KEY-ID" + + There KEY-ID is: + + + + + base64-encoded secret key for commit signing. + + + + + + + ASCII-string used as secret key. + + + + + diff --git a/man/ostree-diff.xml b/man/ostree-diff.xml index 10658cf2..0b7ac892 100644 --- a/man/ostree-diff.xml +++ b/man/ostree-diff.xml @@ -51,7 +51,7 @@ Boston, MA 02111-1307, USA. - ostree diff OPTIONS REV TARGETDIR + ostree diff OPTIONS REV_OR_DIR REV_OR_DIR @@ -59,7 +59,7 @@ Boston, MA 02111-1307, USA. Description - Compare directory TARGETDIR against revision REV. Shows files and directories modified, added, and deleted. If there is a file in TARGETDIR not in REV, it will show with an "A" for "added". If a file in REV is not in TARGETDIR, it shows "D" for "deleted". "M" for "modified" will also show. + Compare a directory or revision against another directory or revision. If REV_OR_DIR starts with `/` or `./`, it is interpreted as a directory, otherwise a revision. Shows files and directories modified, added, and deleted. If there is a file in the second REV_OR_DIR not in the first, it will show with an "A" for "added". If a file in the first REV_OR_DIR is not in the second, it shows "D" for "deleted". "M" for "modified" will also show. diff --git a/man/ostree-find-remotes.xml b/man/ostree-find-remotes.xml index b3796c31..89e278d7 100644 --- a/man/ostree-find-remotes.xml +++ b/man/ostree-find-remotes.xml @@ -116,6 +116,16 @@ Boston, MA 02111-1307, USA. + + + + + Do a mirror pull (see the documentation for + ostree pull --mirror). This option can + only be used in combination with . + + + diff --git a/man/ostree-sign.xml b/man/ostree-sign.xml new file mode 100644 index 00000000..50c0b337 --- /dev/null +++ b/man/ostree-sign.xml @@ -0,0 +1,152 @@ + + + + + + + + + ostree sign + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree sign + 1 + + + + ostree-sign + Sign a commit + + + + + ostree sign OPTIONS COMMIT KEY-ID + + + + + Description + + + Add a new signature to a commit. + + Note that currently, this will append a new signature even if + the commit is already signed with a given key. + + + + There are several "well-known" system places for `ed25519` trusted and revoked public keys -- expected single base64-encoded key per line. + + + Files: + + /etc/ostree/trusted.ed25519 + /etc/ostree/revoked.ed25519 + /usr/share/ostree/trusted.ed25519 + /usr/share/ostree/revoked.ed25519 + + + + Directories containing files with keys: + + /etc/ostree/trusted.ed25519.d + /etc/ostree/revoked.ed25519.d + /usr/share/ostree/trusted.ed25519.d + /usr/share/ostree/rvokeded.ed25519.d + + + + + + Options + + + + + + + + + + base64-encoded secret (for signing) or public key (for verifying). + + + + + + + ASCII-string used as secret key and public key. + + + + + + + + + Verify signatures + + + + + + Use particular signature mechanism. Currently + available ed25519 and dummy + signature types. + + The default is ed25519. + + + + + + Read key(s) from file filename. + + + + Valid for ed25519 signature type. + For ed25519 this file must contain base64-encoded + secret key(s) (for signing) or public key(s) (for verifying) per line. + + + + + + Redefine the system path, where to search files and subdirectories with + well-known and revoked keys. + + + + + diff --git a/man/ostree-summary.xml b/man/ostree-summary.xml index 387dacd7..8305b4e1 100644 --- a/man/ostree-summary.xml +++ b/man/ostree-summary.xml @@ -51,7 +51,7 @@ Boston, MA 02111-1307, USA. - ostree summary --gpg-sign=KEYID --gpg-homedir=HOMEDIR --update --add-metadata=KEY=VALUE + ostree summary --gpg-sign=KEYID --gpg-homedir=HOMEDIR --sign=KEYID --sign-type=ENGINE --update --add-metadata=KEY=VALUE @@ -139,6 +139,39 @@ Boston, MA 02111-1307, USA. + + =ENGINE + + Use particular signature engine. Currently + available ed25519 and dummy + signature types. + + The default is ed25519. + + + + + ="KEY-ID" + + There KEY-ID is: + + + + + base64-encoded secret key for commit signing. + + + + + + + ASCII-string used as secret key. + + + + + + diff --git a/man/ostree.repo-config.xml b/man/ostree.repo-config.xml index 90ac9083..7a01fc01 100644 --- a/man/ostree.repo-config.xml +++ b/man/ostree.repo-config.xml @@ -127,6 +127,18 @@ Boston, MA 02111-1307, USA. + + per-object-fsync + By default, OSTree will batch fsync() after + writing everything; however, this can cause latency spikes + for other processes which are also invoking fsync(). + Turn on this boolean to reduce potential latency spikes, + at the cost of slowing down OSTree updates. You most + likely want this on by default for "background" OS updates. + + + + min-free-space-percent diff --git a/src/boot/grub2/grub2-15_ostree b/src/boot/grub2/grub2-15_ostree index 0b9bf930..9042708e 100644 --- a/src/boot/grub2/grub2-15_ostree +++ b/src/boot/grub2/grub2-15_ostree @@ -26,6 +26,16 @@ if ! test -d /ostree/repo; then exit 0 fi +# Gracefully exit if the grub2 configuration has BLS enabled, +# and the installed version has support for the blscfg module. +# Since there is no need to create menu entries for that case. +# See: https://src.fedoraproject.org/rpms/grub2/c/7c2bab5e98d +. /etc/default/grub +if test -f /boot/grub2/.grub2-blscfg-supported && \ + test "${GRUB_ENABLE_BLSCFG}" = "true"; then + exit 0 +fi + # Make sure we're in the right environment if ! test -n "${GRUB_DEVICE}"; then echo "This script must be run as a child of grub2-mkconfig" 1>&2 diff --git a/src/boot/ostree-finalize-staged.service b/src/boot/ostree-finalize-staged.service index 9c4706e8..90e212b0 100644 --- a/src/boot/ostree-finalize-staged.service +++ b/src/boot/ostree-finalize-staged.service @@ -23,7 +23,7 @@ Documentation=man:ostree(1) ConditionPathExists=/run/ostree-booted DefaultDependencies=no -RequiresMountsFor=/sysroot +RequiresMountsFor=/sysroot /boot After=local-fs.target Before=basic.target final.target # We want to make sure the transaction logs are persisted to disk: @@ -39,3 +39,11 @@ ExecStop=/usr/bin/ostree admin finalize-staged # here is that people don't get an upgrade. We need to handle # cases with slow rotational media, etc. TimeoutStopSec=5m +# OSTree should never touch /var at all...except, we need to remove +# the /var/.updated flag, so we can't just `InaccessiblePaths=/var` right now. +# For now, let's at least use ProtectHome just so we have some sandboxing +# of that. +ProtectHome=yes +# And we shouldn't affect the current deployment's /etc. +ReadOnlyPaths=/etc +# We write to /sysroot and /boot of course. diff --git a/src/boot/ostree-prepare-root.service b/src/boot/ostree-prepare-root.service index 63357581..91692205 100644 --- a/src/boot/ostree-prepare-root.service +++ b/src/boot/ostree-prepare-root.service @@ -23,6 +23,7 @@ ConditionKernelCommandLine=ostree ConditionPathExists=/etc/initrd-release OnFailure=emergency.target After=sysroot.mount +Requires=sysroot.mount Before=initrd-root-fs.target [Service] diff --git a/src/libostree/libostree-devel.sym b/src/libostree/libostree-devel.sym index aa3392cc..2ed658c4 100644 --- a/src/libostree/libostree-devel.sym +++ b/src/libostree/libostree-devel.sym @@ -17,12 +17,6 @@ Boston, MA 02111-1307, USA. ***/ -/* Add new symbols here. Release commits should copy this section into -released.sym. */ -LIBOSTREE_2020.2 { -global: - someostree_symbol_deleteme; -} LIBOSTREE_2020.1; - /* Stub section for the stable release *after* this development one; don't * edit this other than to update the year. This is just a copy/paste * source. Replace $LASTSTABLE with the last stable version, and $NEWVERSION diff --git a/src/libostree/libostree-released.sym b/src/libostree/libostree-released.sym index 33d4d0e3..5c63f78f 100644 --- a/src/libostree/libostree-released.sym +++ b/src/libostree/libostree-released.sym @@ -593,6 +593,28 @@ global: ostree_sysroot_set_mount_namespace_in_use; } LIBOSTREE_2019.6; +/* Add new symbols here. Release commits should copy this section into -released.sym. */ +LIBOSTREE_2020.4 { +global: + ostree_repo_commit_modifier_set_sepolicy_from_commit; + ostree_sign_get_type; + ostree_sign_get_all; + ostree_sign_commit; + ostree_sign_commit_verify; + ostree_sign_data; + ostree_sign_data_verify; + ostree_sign_get_by_name; + ostree_sign_get_name; + ostree_sign_clear_keys; + ostree_sign_load_pk; + ostree_sign_metadata_format; + ostree_sign_metadata_key; + ostree_sign_set_pk; + ostree_sign_add_pk; + ostree_sign_set_sk; + ostree_sign_summary; +} LIBOSTREE_2020.1; + /* No new symbols in 2020.2 */ /* NOTE: Only add more content here in release commits! See the diff --git a/src/libostree/ostree-autocleanups.h b/src/libostree/ostree-autocleanups.h index c9692ebe..14017012 100644 --- a/src/libostree/ostree-autocleanups.h +++ b/src/libostree/ostree-autocleanups.h @@ -73,6 +73,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderOverride, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderResult, ostree_repo_finder_result_free) G_DEFINE_AUTO_CLEANUP_FREE_FUNC (OstreeRepoFinderResultv, ostree_repo_finder_result_freev, NULL) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSign, g_object_unref) #endif G_END_DECLS diff --git a/src/libostree/ostree-bootloader-uboot.c b/src/libostree/ostree-bootloader-uboot.c index 4cd955d5..1e1f0371 100644 --- a/src/libostree/ostree-bootloader-uboot.c +++ b/src/libostree/ostree-bootloader-uboot.c @@ -144,6 +144,10 @@ create_config_from_boot_loader_entries (OstreeBootloaderUboot *self, if (val) g_ptr_array_add (new_lines, g_strdup_printf ("fdt_file%s=%s", index_suffix, val)); + val = ostree_bootconfig_parser_get (config, "fdtdir"); + if (val) + g_ptr_array_add (new_lines, g_strdup_printf ("fdtdir%s=%s", index_suffix, val)); + val = ostree_bootconfig_parser_get (config, "options"); if (val) { diff --git a/src/libostree/ostree-cmdprivate.c b/src/libostree/ostree-cmdprivate.c index de82521c..86793790 100644 --- a/src/libostree/ostree-cmdprivate.c +++ b/src/libostree/ostree-cmdprivate.c @@ -24,7 +24,6 @@ #include "ostree-cmdprivate.h" #include "ostree-repo-private.h" #include "ostree-core-private.h" -#include "ostree-repo-pull-private.h" #include "ostree-repo-static-delta-private.h" #include "ostree-sysroot-private.h" #include "ostree-bootloader-grub2.h" diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c index 48815bd3..523f57c0 100644 --- a/src/libostree/ostree-core.c +++ b/src/libostree/ostree-core.c @@ -2376,6 +2376,13 @@ ostree_commit_get_parent (GVariant *commit_variant) return ostree_checksum_from_bytes_v (bytes); } +/** + * ostree_commit_get_timestamp: + * @commit_variant: Commit object + * + * Returns: timestamp in seconds since the Unix epoch, UTC + * Since: 2016.3 + */ guint64 ostree_commit_get_timestamp (GVariant *commit_variant) { diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h index 540f3232..3b903d5c 100644 --- a/src/libostree/ostree-core.h +++ b/src/libostree/ostree-core.h @@ -212,6 +212,19 @@ typedef enum { * Since: 2014.9 */ #define OSTREE_COMMIT_META_KEY_VERSION "version" + +/** + * OSTREE_COMMIT_META_KEY_ARCHITECTURE: + * + * GVariant type `s`. Intended to describe the CPU architecture. This is a freeform string, and some distributions + * which have existing package managers might want to match that schema. If you + * don't have a prior schema, it's recommended to use `uname -m` by default (i.e. the Linux kernel schema). In the future + * ostree might include a builtin function to compare architectures. + * + * Since: 2020.4 + */ +#define OSTREE_COMMIT_META_KEY_ARCHITECTURE "ostree.architecture" + /** * OSTREE_COMMIT_META_KEY_ENDOFLIFE_REBASE: * diff --git a/src/libostree/ostree-fetcher-util.c b/src/libostree/ostree-fetcher-util.c index a9bd60a5..1c3f8104 100644 --- a/src/libostree/ostree-fetcher-util.c +++ b/src/libostree/ostree-fetcher-util.c @@ -202,6 +202,7 @@ _ostree_fetcher_should_retry_request (const GError *error, if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT) || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_HOST_NOT_FOUND) || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE) || + g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT) || #if !GLIB_CHECK_VERSION(2, 44, 0) g_error_matches (error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE) || #else diff --git a/src/libostree/ostree-gpg-verify-result.h b/src/libostree/ostree-gpg-verify-result.h index 6f51ce8a..8f243fcd 100644 --- a/src/libostree/ostree-gpg-verify-result.h +++ b/src/libostree/ostree-gpg-verify-result.h @@ -134,7 +134,7 @@ GVariant * ostree_gpg_verify_result_get_all (OstreeGpgVerifyResult *result, * for future variations. **/ typedef enum { - OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT = 0 + OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT = (0 << 0), } OstreeGpgSignatureFormatFlags; _OSTREE_PUBLIC diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index dac4573c..0c9de239 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -51,15 +51,33 @@ #define FICLONE _IOW(0x94, 9, int) #endif - -/* If fsync is enabled and we're in a txn, we write into a staging dir for - * commit, but we also allow direct writes into objects/ for e.g. hardlink - * imports. +/* Understanding ostree's fsync strategy + * + * A long time ago, ostree used to invoke fsync() on each object, + * then move it into the objects directory. However, it turned + * out to be a *lot* faster to write the objects into a separate "staging" + * directory (letting the filesystem handle writeback how it likes) + * and then only walk over each of the files, fsync(), then rename() + * into place. See also https://lwn.net/Articles/789024/ + * + * (We also support a "disable fsync entirely" mode, where you don't + * care about integrity; e.g. test suites using disposable VMs). + * + * This "delayed fsync" pattern though is much worse for other concurrent processes + * like databases because it forces a lot to go through the filesystem + * journal at once once we do the sync. So now we support a `per_object_fsync` + * option that again invokes `fsync()` directly. This also notably + * provides "backpressure", ensuring we aren't queuing up a huge amount + * of I/O at once. */ + +/* The directory where we place content */ static int commit_dest_dfd (OstreeRepo *self) { - if (self->in_transaction && !self->disable_fsync) + if (self->per_object_fsync) + return self->objects_dir_fd; + else if (self->in_transaction && !self->disable_fsync) return self->commit_stagedir.fd; else return self->objects_dir_fd; @@ -420,7 +438,7 @@ commit_loose_regfile_object (OstreeRepo *self, /* Ensure that in case of a power cut, these files have the data we * want. See http://lwn.net/Articles/322823/ */ - if (!self->in_transaction && !self->disable_fsync) + if (!self->disable_fsync && self->per_object_fsync) { if (fsync (tmpf->fd) == -1) return glnx_throw_errno_prefix (error, "fsync"); @@ -1835,6 +1853,52 @@ ostree_repo_prepare_transaction (OstreeRepo *self, return TRUE; } +/* Synchronize the directories holding the objects */ +static gboolean +fsync_object_dirs (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("fsync objdirs", error); + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + + if (self->disable_fsync) + return TRUE; /* No fsync? Nothing to do then. */ + + if (!glnx_dirfd_iterator_init_at (self->objects_dir_fd, ".", FALSE, &dfd_iter, error)) + return FALSE; + while (TRUE) + { + struct dirent *dent; + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + if (dent->d_type != DT_DIR) + continue; + /* All object directories only have two character entries */ + if (strlen (dent->d_name) != 2) + continue; + + glnx_autofd int target_dir_fd = -1; + if (!glnx_opendirat (self->objects_dir_fd, dent->d_name, FALSE, + &target_dir_fd, error)) + return FALSE; + /* This synchronizes the directory to ensure all the objects we wrote + * are there. We need to do this before removing the .commitpartial + * stamp (or have a ref point to the commit). + */ + if (fsync (target_dir_fd) == -1) + return glnx_throw_errno_prefix (error, "fsync"); + } + + /* In case we created any loose object subdirs, make sure they are on disk */ + if (fsync (self->objects_dir_fd) == -1) + return glnx_throw_errno_prefix (error, "fsync"); + + return TRUE; +} + /* Called for commit, to iterate over the "staging" directory and rename all the * objects into the primary objects/ location. Notably this is called only after * syncfs() has potentially been invoked to ensure that all objects have been @@ -1856,10 +1920,6 @@ rename_pending_loose_objects (OstreeRepo *self, while (TRUE) { struct dirent *dent; - gboolean renamed_some_object = FALSE; - g_auto(GLnxDirFdIterator) child_dfd_iter = { 0, }; - char loose_objpath[_OSTREE_LOOSE_PATH_MAX]; - if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) return FALSE; if (dent == NULL) @@ -1872,10 +1932,12 @@ rename_pending_loose_objects (OstreeRepo *self, if (strlen (dent->d_name) != 2) continue; + g_auto(GLnxDirFdIterator) child_dfd_iter = { 0, }; if (!glnx_dirfd_iterator_init_at (dfd_iter.fd, dent->d_name, FALSE, &child_dfd_iter, error)) return FALSE; + char loose_objpath[_OSTREE_LOOSE_PATH_MAX]; loose_objpath[0] = dent->d_name[0]; loose_objpath[1] = dent->d_name[1]; loose_objpath[2] = '/'; @@ -1899,41 +1961,13 @@ rename_pending_loose_objects (OstreeRepo *self, if (!glnx_renameat (child_dfd_iter.fd, loose_objpath + 3, self->objects_dir_fd, loose_objpath, error)) return FALSE; - - renamed_some_object = TRUE; } - - if (renamed_some_object && !self->disable_fsync) - { - /* Ensure that in the case of a power cut all the directory metadata that - we want has reached the disk. In particular, we want this before we - update the refs to point to these objects. */ - glnx_autofd int target_dir_fd = -1; - - loose_objpath[2] = 0; - - if (!glnx_opendirat (self->objects_dir_fd, - loose_objpath, FALSE, - &target_dir_fd, - error)) - return FALSE; - - if (fsync (target_dir_fd) == -1) - return glnx_throw_errno_prefix (error, "fsync"); - } - } - - /* In case we created any loose object subdirs, make sure they are on disk */ - if (!self->disable_fsync) - { - if (fsync (self->objects_dir_fd) == -1) - return glnx_throw_errno_prefix (error, "fsync"); } return TRUE; } -/* Try to lock a transaction stage directory created by +/* Try to lock and delete a transaction stage directory created by * ostree_repo_prepare_transaction(). */ static gboolean @@ -1943,6 +1977,9 @@ cleanup_txn_dir (OstreeRepo *self, GCancellable *cancellable, GError **error) { + const char *errprefix = glnx_strjoina ("Cleaning up txn dir ", path); + GLNX_AUTO_PREFIX_ERROR (errprefix, error); + g_auto(GLnxLockFile) lockfile = { 0, }; gboolean did_lock; @@ -2008,7 +2045,7 @@ cleanup_tmpdir (OstreeRepo *self, continue; /* Handle transaction tmpdirs */ - if (_ostree_repo_is_locked_tmpdir (dent->d_name)) + if (_ostree_repo_has_staging_prefix (dent->d_name) && S_ISDIR (stbuf.st_mode)) { if (!cleanup_txn_dir (self, dfd_iter.fd, dent->d_name, cancellable, error)) return FALSE; @@ -2374,6 +2411,9 @@ ostree_repo_commit_transaction (OstreeRepo *self, if (!rename_pending_loose_objects (self, cancellable, error)) return FALSE; + if (!fsync_object_dirs (self, cancellable, error)) + return FALSE; + g_debug ("txn commit %s", glnx_basename (self->commit_stagedir.path)); if (!glnx_tmpdir_delete (&self->commit_stagedir, cancellable, error)) return FALSE; @@ -4227,9 +4267,11 @@ ostree_repo_commit_modifier_unref (OstreeRepoCommitModifier *modifier) if (modifier->xattr_destroy) modifier->xattr_destroy (modifier->xattr_user_data); - g_clear_object (&modifier->sepolicy); g_clear_pointer (&modifier->devino_cache, (GDestroyNotify)g_hash_table_unref); + g_clear_object (&modifier->sepolicy); + (void) glnx_tmpdir_delete (&modifier->sepolicy_tmpdir, NULL, NULL); + g_free (modifier); return; } @@ -4279,6 +4321,60 @@ ostree_repo_commit_modifier_set_sepolicy (OstreeRepoCommitModifier modifier->sepolicy = sepolicy ? g_object_ref (sepolicy) : NULL; } +/** + * ostree_repo_commit_modifier_set_sepolicy_from_commit: + * @modifier: Commit modifier + * @repo: OSTree repo containing @rev + * @rev: Find SELinux policy from this base commit + * @cancellable: + * @error: + * + * In many cases, one wants to create a "derived" commit from base commit. + * SELinux policy labels are part of that base commit. This API allows + * one to easily set up SELinux labeling from a base commit. + */ +gboolean +ostree_repo_commit_modifier_set_sepolicy_from_commit (OstreeRepoCommitModifier *modifier, + OstreeRepo *repo, + const char *rev, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("setting sepolicy from commit", error); + g_autofree char *commit = NULL; + g_autoptr(GFile) root = NULL; + if (!ostree_repo_read_commit (repo, rev, &root, &commit, cancellable, error)) + return FALSE; + const char policypath[] = "usr/etc/selinux"; + g_autoptr(GFile) policyroot = g_file_get_child (root, policypath); + if (!g_file_query_exists (policyroot, NULL)) + return TRUE; /* No policy, nothing to do */ + + GLnxTmpDir tmpdir = {0,}; + if (!glnx_mkdtemp ("ostree-commit-sepolicy-XXXXXX", 0700, &tmpdir, error)) + return FALSE; + if (!glnx_shutil_mkdir_p_at (tmpdir.fd, "usr/etc", 0755, cancellable, error)) + return FALSE; + + OstreeRepoCheckoutAtOptions coopts = {0,}; + coopts.mode = OSTREE_REPO_CHECKOUT_MODE_USER; + coopts.subpath = glnx_strjoina ("/", policypath); + + if (!ostree_repo_checkout_at (repo, &coopts, tmpdir.fd, policypath, commit, cancellable, error)) + return glnx_prefix_error (error, "policy checkout"); + + g_autoptr(OstreeSePolicy) policy = ostree_sepolicy_new_at (tmpdir.fd, cancellable, error); + if (!policy) + return glnx_prefix_error (error, "reading policy"); + + ostree_repo_commit_modifier_set_sepolicy (modifier, policy); + /* Transfer ownership */ + modifier->sepolicy_tmpdir = tmpdir; + tmpdir.initialized = FALSE; + + return TRUE; +} + /** * ostree_repo_commit_modifier_set_devino_cache: * @modifier: Modifier diff --git a/src/libostree/ostree-repo-deprecated.h b/src/libostree/ostree-repo-deprecated.h index 4265aa97..1c9d2251 100644 --- a/src/libostree/ostree-repo-deprecated.h +++ b/src/libostree/ostree-repo-deprecated.h @@ -24,9 +24,11 @@ #include "ostree-core.h" #include "ostree-types.h" +#ifndef __GI_SCANNER__ #ifndef G_GNUC_DEPRECATED_FOR # define G_GNUC_DEPRECATED_FOR(x) #endif +#endif G_BEGIN_DECLS diff --git a/src/libostree/ostree-repo-finder-avahi.c b/src/libostree/ostree-repo-finder-avahi.c index f8d1f878..1b085ea0 100644 --- a/src/libostree/ostree-repo-finder-avahi.c +++ b/src/libostree/ostree-repo-finder-avahi.c @@ -1358,7 +1358,7 @@ ostree_repo_finder_avahi_init (OstreeRepoFinderAvahi *self) } /** - * ostree_repo-finder_avahi_new: + * ostree_repo_finder_avahi_new: * @context: (transfer none) (nullable): a #GMainContext for processing Avahi * events in, or %NULL to use the current thread-default * diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h index 571cab6b..8c1f5071 100644 --- a/src/libostree/ostree-repo-private.h +++ b/src/libostree/ostree-repo-private.h @@ -38,13 +38,17 @@ G_BEGIN_DECLS #define _OSTREE_MAX_OUTSTANDING_FETCHER_REQUESTS 8 #define _OSTREE_MAX_OUTSTANDING_DELTAPART_REQUESTS 2 -/* In most cases, writing to disk should be much faster than - * fetching from the network, so we shouldn't actually hit - * this. But if using pipelining and e.g. pulling over LAN - * (or writing to slow media), we can have a runaway - * situation towards EMFILE. +/* We want some parallelism with disk writes, but we also + * want to avoid starting tens or hundreds of threads + * (via GTask) all writing to disk. Eventually we may + * use io_uring which handles backpressure correctly. + * Also, in "immediate fsync" mode, this helps provide + * much more backpressure, helping our I/O patterns + * be nicer for any concurrent processes, such as etcd + * or other databases. + * https://github.com/openshift/machine-config-operator/issues/1897 * */ -#define _OSTREE_MAX_OUTSTANDING_WRITE_REQUESTS 16 +#define _OSTREE_MAX_OUTSTANDING_WRITE_REQUESTS 3 /* Well-known keys for the additional metadata field in a summary file. */ #define OSTREE_SUMMARY_LAST_MODIFIED "ostree.summary.last-modified" @@ -76,6 +80,7 @@ struct OstreeRepoCommitModifier { GDestroyNotify xattr_destroy; gpointer xattr_user_data; + GLnxTmpDir sepolicy_tmpdir; OstreeSePolicy *sepolicy; GHashTable *devino_cache; }; @@ -146,6 +151,7 @@ struct OstreeRepo { GError *writable_error; gboolean in_transaction; gboolean disable_fsync; + gboolean per_object_fsync; gboolean disable_xattrs; guint zlib_compression_level; GHashTable *loose_object_devino_hash; @@ -246,7 +252,7 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd, GError **error); gboolean -_ostree_repo_is_locked_tmpdir (const char *filename); +_ostree_repo_has_staging_prefix (const char *filename); gboolean _ostree_repo_try_lock_tmpdir (int tmpdir_dfd, @@ -373,9 +379,9 @@ _ostree_repo_verify_commit_internal (OstreeRepo *self, #endif /* OSTREE_DISABLE_GPGME */ typedef enum { - _OSTREE_REPO_IMPORT_FLAGS_NONE, - _OSTREE_REPO_IMPORT_FLAGS_TRUSTED, - _OSTREE_REPO_IMPORT_FLAGS_VERIFY_BAREUSERONLY, + _OSTREE_REPO_IMPORT_FLAGS_NONE = 0, + _OSTREE_REPO_IMPORT_FLAGS_TRUSTED = (1 << 0), + _OSTREE_REPO_IMPORT_FLAGS_VERIFY_BAREUSERONLY = (1 << 1), } OstreeRepoImportFlags; gboolean @@ -501,4 +507,10 @@ _ostree_tmpf_fsverity (OstreeRepo *self, GLnxTmpfile *tmpf, GError **error); +gboolean +_ostree_repo_verify_bindings (const char *collection_id, + const char *ref_name, + GVariant *commit, + GError **error); + G_END_DECLS diff --git a/src/libostree/ostree-repo-pull-private.h b/src/libostree/ostree-repo-pull-private.h index f50697b9..689118be 100644 --- a/src/libostree/ostree-repo-pull-private.h +++ b/src/libostree/ostree-repo-pull-private.h @@ -21,14 +21,151 @@ #pragma once -#include "ostree-core.h" +#include "ostree-repo-private.h" +#include "ostree-fetcher-util.h" +#include "ostree-remote-private.h" G_BEGIN_DECLS +typedef enum { + OSTREE_FETCHER_SECURITY_STATE_CA_PINNED, + OSTREE_FETCHER_SECURITY_STATE_TLS, + OSTREE_FETCHER_SECURITY_STATE_INSECURE, +} OstreeFetcherSecurityState; + +typedef struct { + OstreeRepo *repo; + int tmpdir_dfd; + OstreeRepoPullFlags flags; + char *remote_name; + char *remote_refspec_name; + OstreeRepoMode remote_mode; + OstreeFetcher *fetcher; + OstreeFetcherSecurityState fetcher_security_state; + + GPtrArray *meta_mirrorlist; /* List of base URIs for fetching metadata */ + GPtrArray *content_mirrorlist; /* List of base URIs for fetching content */ + OstreeRepo *remote_repo_local; + GPtrArray *localcache_repos; /* Array */ + + GMainContext *main_context; + GCancellable *cancellable; + OstreeAsyncProgress *progress; + + GVariant *extra_headers; + char *append_user_agent; + + gboolean dry_run; + gboolean dry_run_emitted_progress; + gboolean legacy_transaction_resuming; + guint n_network_retries; + enum { + OSTREE_PULL_PHASE_FETCHING_REFS, + OSTREE_PULL_PHASE_FETCHING_OBJECTS + } phase; + gint n_scanned_metadata; + + gboolean gpg_verify; + gboolean gpg_verify_summary; + gboolean require_static_deltas; + gboolean disable_static_deltas; + gboolean has_tombstone_commits; + + GBytes *summary_data; + GBytes *summary_data_sig; + GVariant *summary; + GHashTable *summary_deltas_checksums; + GHashTable *ref_original_commits; /* Maps checksum to commit, used by timestamp checks */ + GHashTable *verified_commits; /* Set of commits that have been verified */ + GHashTable *signapi_verified_commits; /* Map of commits that have been signapi verified */ + GHashTable *ref_keyring_map; /* Maps OstreeCollectionRef to keyring remote name */ + GPtrArray *static_delta_superblocks; + GHashTable *expected_commit_sizes; /* Maps commit checksum to known size */ + GHashTable *commit_to_depth; /* Maps commit checksum maximum depth */ + GHashTable *scanned_metadata; /* Maps object name to itself */ + GHashTable *fetched_detached_metadata; /* Map */ + GHashTable *requested_metadata; /* Maps object name to itself */ + GHashTable *requested_content; /* Maps checksum to itself */ + GHashTable *requested_fallback_content; /* Maps checksum to itself */ + GHashTable *pending_fetch_metadata; /* Map */ + GHashTable *pending_fetch_content; /* Map */ + GHashTable *pending_fetch_delta_superblocks; /* Set */ + GHashTable *pending_fetch_deltaparts; /* Set */ + guint n_outstanding_metadata_fetches; + guint n_outstanding_metadata_write_requests; + guint n_outstanding_content_fetches; + guint n_outstanding_content_write_requests; + guint n_outstanding_deltapart_fetches; + guint n_outstanding_deltapart_write_requests; + guint n_total_deltaparts; + guint n_total_delta_fallbacks; + guint64 fetched_deltapart_size; /* How much of the delta we have now */ + guint64 total_deltapart_size; + guint64 total_deltapart_usize; + gint n_requested_metadata; + gint n_requested_content; + guint n_fetched_deltaparts; + guint n_fetched_deltapart_fallbacks; + guint n_fetched_metadata; + guint n_fetched_content; + /* Objects imported via hardlink/reflink/copying or --localcache-repo*/ + guint n_imported_metadata; + guint n_imported_content; + + gboolean timestamp_check; /* Verify commit timestamps */ + char *timestamp_check_from_rev; + int maxdepth; + guint64 max_metadata_size; + guint64 start_time; + + gboolean is_mirror; + gboolean trusted_http_direct; + gboolean is_commit_only; + OstreeRepoImportFlags importflags; + + GPtrArray *signapi_commit_verifiers; + GPtrArray *signapi_summary_verifiers; + + GPtrArray *dirs; + + gboolean have_previous_bytes; + guint64 previous_bytes_sec; + guint64 previous_total_downloaded; + + GError *cached_async_error; + GError **async_error; + gboolean caught_error; + + GQueue scan_object_queue; + GSource *idle_src; +} OtPullData; + gboolean -_ostree_repo_verify_bindings (const char *collection_id, - const char *ref_name, - GVariant *commit, - GError **error); +_signapi_init_for_remote (OstreeRepo *repo, + const char *remote_name, + GPtrArray **out_commit_verifiers, + GPtrArray **out_summary_verifiers, + GError **error); +gboolean +_sign_verify_for_remote (GPtrArray *signers, + GBytes *signed_data, + GVariant *metadata, + char **out_success_message, + GError **error); + +gboolean +_verify_unwritten_commit (OtPullData *pull_data, + const char *checksum, + GVariant *commit, + GVariant *detached_metadata, + const OstreeCollectionRef *ref, + GCancellable *cancellable, + GError **error); + +gboolean +_process_gpg_verify_result (OtPullData *pull_data, + const char *checksum, + OstreeGpgVerifyResult *result, + GError **error); G_END_DECLS diff --git a/src/libostree/ostree-repo-pull-verify.c b/src/libostree/ostree-repo-pull-verify.c new file mode 100644 index 00000000..fa170f94 --- /dev/null +++ b/src/libostree/ostree-repo-pull-verify.c @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2020 Red Hat, Inc. + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "libglnx.h" +#include "ostree.h" +#include "otutil.h" +#include "ostree-repo-pull-private.h" +#include "ostree-repo-private.h" + +#include "ostree-core-private.h" +#include "ostree-repo-static-delta-private.h" +#include "ostree-metalink.h" +#include "ostree-fetcher-util.h" +#include "ostree-remote-private.h" +#include "ot-fs-utils.h" + +#include +#include +#ifdef HAVE_LIBSYSTEMD +#include +#endif + +#include "ostree-sign.h" + +static gboolean +get_signapi_remote_option (OstreeRepo *repo, + OstreeSign *sign, + const char *remote_name, + const char *keysuffix, + char **out_value, + GError **error) +{ + g_autofree char *key = g_strdup_printf ("verification-%s-%s", ostree_sign_get_name (sign), keysuffix); + return ostree_repo_get_remote_option (repo, remote_name, key, NULL, out_value, error); +} + +/* _signapi_load_public_keys: + * + * Load public keys according remote's configuration: + * inlined key passed via config option `verification--key` or + * file name with public keys via `verification--file` option. + * + * If both options are set then load all all public keys + * both from file and inlined in config. + * + * Returns: %FALSE if any source is configured but nothing has been loaded. + * Returns: %TRUE if no configuration or any key loaded. + * */ +static gboolean +_signapi_load_public_keys (OstreeSign *sign, + OstreeRepo *repo, + const gchar *remote_name, + gboolean required, + GError **error) +{ + g_autofree gchar *pk_ascii = NULL; + g_autofree gchar *pk_file = NULL; + gboolean loaded_from_file = TRUE; + gboolean loaded_inlined = TRUE; + + if (!get_signapi_remote_option (repo, sign, remote_name, "file", &pk_file, error)) + return FALSE; + if (!get_signapi_remote_option (repo, sign, remote_name, "key", &pk_ascii, error)) + return FALSE; + + /* return TRUE if there is no configuration for remote */ + if ((pk_file == NULL) &&(pk_ascii == NULL)) + { + /* It is expected what remote may have verification file as + * a part of configuration. Hence there is not a lot of sense + * for automatic resolve of per-remote keystore file as it + * used in find_keyring () for GPG. + * If it is needed to add the similar mechanism, it is preferable + * to pass the path to ostree_sign_load_pk () via GVariant options + * and call it here for loading with method and file structure + * specific for signature type. + */ + if (required) + return glnx_throw (error, "No keys found for required signapi type %s", ostree_sign_get_name (sign)); + return TRUE; + } + + if (pk_file != NULL) + { + g_autoptr (GError) local_error = NULL; + g_autoptr (GVariantBuilder) builder = NULL; + g_autoptr (GVariant) options = NULL; + + builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (builder, "{sv}", "filename", g_variant_new_string (pk_file)); + options = g_variant_builder_end (builder); + + if (ostree_sign_load_pk (sign, options, &local_error)) + loaded_from_file = TRUE; + else + { + return glnx_throw (error, "Failed loading '%s' keys from '%s", + ostree_sign_get_name (sign), pk_file); + } + } + + if (pk_ascii != NULL) + { + g_autoptr (GError) local_error = NULL; + g_autoptr (GVariant) pk = g_variant_new_string(pk_ascii); + + /* Add inlined public key */ + if (loaded_from_file) + loaded_inlined = ostree_sign_add_pk (sign, pk, &local_error); + else + loaded_inlined = ostree_sign_set_pk (sign, pk, &local_error); + + if (!loaded_inlined) + { + return glnx_throw (error, "Failed loading '%s' keys from inline `verification-key`", + ostree_sign_get_name (sign)); + } + } + + /* Return true if able to load from any source */ + if (!(loaded_from_file || loaded_inlined)) + return glnx_throw (error, "No keys found"); + + return TRUE; +} + +static gboolean +string_is_gkeyfile_truthy (const char *value, + gboolean *out_truth) +{ + /* See https://gitlab.gnome.org/GNOME/glib/-/blob/20fb5bf868added5aec53c013ae85ec78ba2eedc/glib/gkeyfile.c#L4528 */ + if (g_str_equal (value, "true") || g_str_equal (value, "1")) + { + *out_truth = TRUE; + return TRUE; + } + else if (g_str_equal (value, "false") || g_str_equal (value, "0")) + { + *out_truth = FALSE; + return TRUE; + } + return FALSE; +} + +static gboolean +verifiers_from_config (OstreeRepo *repo, + const char *remote_name, + const char *key, + GPtrArray **out_verifiers, + GError **error) +{ + g_autoptr(GPtrArray) verifiers = NULL; + + g_autofree char *raw_value = NULL; + if (!ostree_repo_get_remote_option (repo, remote_name, + key, NULL, + &raw_value, error)) + return FALSE; + if (raw_value == NULL || g_str_equal (raw_value, "")) + { + *out_verifiers = NULL; + return TRUE; + } + gboolean sign_verify_bool = FALSE; + /* Is the value "truthy" according to GKeyFile's rules? If so, + * then we take this to be "accept signatures from any compiled + * type that happens to have keys configured". + */ + if (string_is_gkeyfile_truthy (raw_value, &sign_verify_bool)) + { + if (sign_verify_bool) + { + verifiers = ostree_sign_get_all (); + for (guint i = 0; i < verifiers->len; i++) + { + OstreeSign *sign = verifiers->pdata[i]; + /* Try to load public key(s) according remote's configuration; + * this one is optional. + */ + if (!_signapi_load_public_keys (sign, repo, remote_name, FALSE, error)) + return FALSE; + } + } + } + else + { + /* If the value isn't "truthy", then it must be an explicit list */ + g_auto(GStrv) sign_types = NULL; + if (!ostree_repo_get_remote_list_option (repo, remote_name, + key, &sign_types, + error)) + return FALSE; + verifiers = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (char **iter = sign_types; iter && *iter; iter++) + { + const char *sign_type = *iter; + OstreeSign *verifier = ostree_sign_get_by_name (sign_type, error); + if (!verifier) + return FALSE; + if (!_signapi_load_public_keys (verifier, repo, remote_name, TRUE, error)) + return FALSE; + g_ptr_array_add (verifiers, verifier); + } + g_assert_cmpuint (verifiers->len, >=, 1); + } + + *out_verifiers = g_steal_pointer (&verifiers); + return TRUE; +} + +/* Create a new array of OstreeSign objects and load the public + * keys as described by the remote configuration. If the + * remote does not have signing verification enabled, then + * the resulting verifier list will be NULL. + */ +gboolean +_signapi_init_for_remote (OstreeRepo *repo, + const char *remote_name, + GPtrArray **out_commit_verifiers, + GPtrArray **out_summary_verifiers, + GError **error) +{ + g_autoptr(GPtrArray) commit_verifiers = NULL; + g_autoptr(GPtrArray) summary_verifiers = NULL; + + if (!verifiers_from_config (repo, remote_name, "sign-verify", &commit_verifiers, error)) + return FALSE; + if (!verifiers_from_config (repo, remote_name, "sign-verify-summary", &summary_verifiers, error)) + return FALSE; + + ot_transfer_out_value (out_commit_verifiers, &commit_verifiers); + ot_transfer_out_value (out_summary_verifiers, &summary_verifiers); + return TRUE; +} + +/* Iterate over the configured verifiers, and require the commit is signed + * by at least one. + */ +gboolean +_sign_verify_for_remote (GPtrArray *verifiers, + GBytes *signed_data, + GVariant *metadata, + char **out_success_message, + GError **error) +{ + guint n_invalid_signatures = 0; + g_autoptr (GError) last_sig_error = NULL; + gboolean found_sig = FALSE; + + g_assert (out_success_message == NULL || *out_success_message == NULL); + + g_assert_cmpuint (verifiers->len, >=, 1); + for (guint i = 0; i < verifiers->len; i++) + { + OstreeSign *sign = verifiers->pdata[i]; + const gchar *signature_key = ostree_sign_metadata_key (sign); + GVariantType *signature_format = (GVariantType *) ostree_sign_metadata_format (sign); + g_autoptr (GVariant) signatures = + g_variant_lookup_value (metadata, signature_key, signature_format); + + /* If not found signatures for requested signature subsystem */ + if (!signatures) + continue; + + found_sig = TRUE; + + g_autofree char *success_message = NULL; + /* Return true if any signature fit to pre-loaded public keys. + * If no keys configured -- then system configuration will be used */ + if (!ostree_sign_data_verify (sign, + signed_data, + signatures, + &success_message, + last_sig_error ? NULL : &last_sig_error)) + { + n_invalid_signatures++; + continue; + } + /* Accept the first valid signature */ + if (out_success_message) + *out_success_message = g_steal_pointer (&success_message); + return TRUE; + } + + if (!found_sig) + return glnx_throw (error, "No signatures found"); + + g_assert (last_sig_error); + g_propagate_error (error, g_steal_pointer (&last_sig_error)); + if (n_invalid_signatures > 1) + glnx_prefix_error (error, "(%d other invalid signatures)", n_invalid_signatures-1); + return FALSE; +} + + +#ifndef OSTREE_DISABLE_GPGME +gboolean +_process_gpg_verify_result (OtPullData *pull_data, + const char *checksum, + OstreeGpgVerifyResult *result, + GError **error) +{ + const char *error_prefix = glnx_strjoina ("Commit ", checksum); + GLNX_AUTO_PREFIX_ERROR(error_prefix, error); + if (result == NULL) + return FALSE; + + /* Allow callers to output the results immediately. */ + g_signal_emit_by_name (pull_data->repo, + "gpg-verify-result", + checksum, result); + + if (!ostree_gpg_verify_result_require_valid_signature (result, error)) + return FALSE; + + + /* We now check both *before* writing the commit, and after. Because the + * behavior used to be only verifiying after writing, we need to handle + * the case of "written but not verified". But we also don't want to check + * twice, as that'd result in duplicate signals. + */ + g_hash_table_add (pull_data->verified_commits, g_strdup (checksum)); + + return TRUE; +} +#endif /* OSTREE_DISABLE_GPGME */ + +gboolean +_verify_unwritten_commit (OtPullData *pull_data, + const char *checksum, + GVariant *commit, + GVariant *detached_metadata, + const OstreeCollectionRef *ref, + GCancellable *cancellable, + GError **error) +{ + /* Shouldn't happen, but see comment in process_gpg_verify_result() */ + if ((!pull_data->gpg_verify || g_hash_table_contains (pull_data->verified_commits, checksum)) + && (!pull_data->signapi_commit_verifiers || g_hash_table_contains (pull_data->signapi_verified_commits, checksum))) + return TRUE; + + g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes (commit); + +#ifndef OSTREE_DISABLE_GPGME + if (pull_data->gpg_verify) + { + const char *keyring_remote = NULL; + + if (ref != NULL) + keyring_remote = g_hash_table_lookup (pull_data->ref_keyring_map, ref); + if (keyring_remote == NULL) + keyring_remote = pull_data->remote_name; + + g_autoptr(OstreeGpgVerifyResult) result = + _ostree_repo_gpg_verify_with_metadata (pull_data->repo, signed_data, + detached_metadata, + keyring_remote, + NULL, NULL, cancellable, error); + if (!_process_gpg_verify_result (pull_data, checksum, result, error)) + return FALSE; + } +#endif /* OSTREE_DISABLE_GPGME */ + + if (pull_data->signapi_commit_verifiers) + { + /* Nothing to check if detached metadata is absent */ + if (detached_metadata == NULL) + return glnx_throw (error, "Can't verify commit without detached metadata"); + + g_autofree char *success_message = NULL; + if (!_sign_verify_for_remote (pull_data->signapi_commit_verifiers, signed_data, detached_metadata, &success_message, error)) + return glnx_prefix_error (error, "Can't verify commit"); + + /* Mark the commit as verified to avoid double verification + * see process_verify_result () for rationale */ + g_hash_table_insert (pull_data->signapi_verified_commits, g_strdup (checksum), g_steal_pointer (&success_message)); + } + + return TRUE; +} diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c index 125c113d..5fdbeabc 100644 --- a/src/libostree/ostree-repo-pull.c +++ b/src/libostree/ostree-repo-pull.c @@ -30,16 +30,12 @@ #include "ostree.h" #include "otutil.h" #include "ostree-repo-pull-private.h" -#include "ostree-repo-private.h" #ifdef HAVE_LIBCURL_OR_LIBSOUP #include "ostree-core-private.h" #include "ostree-repo-static-delta-private.h" #include "ostree-metalink.h" -#include "ostree-fetcher-util.h" -#include "ostree-remote-private.h" -#include "ot-fs-utils.h" #include "ostree-repo-finder.h" #include "ostree-repo-finder-config.h" @@ -65,114 +61,6 @@ * `n-network-retries` pull option. */ #define DEFAULT_N_NETWORK_RETRIES 5 -typedef enum { - OSTREE_FETCHER_SECURITY_STATE_CA_PINNED, - OSTREE_FETCHER_SECURITY_STATE_TLS, - OSTREE_FETCHER_SECURITY_STATE_INSECURE, -} OstreeFetcherSecurityState; - -typedef struct { - OstreeRepo *repo; - int tmpdir_dfd; - OstreeRepoPullFlags flags; - char *remote_name; - char *remote_refspec_name; - OstreeRepoMode remote_mode; - OstreeFetcher *fetcher; - OstreeFetcherSecurityState fetcher_security_state; - - GPtrArray *meta_mirrorlist; /* List of base URIs for fetching metadata */ - GPtrArray *content_mirrorlist; /* List of base URIs for fetching content */ - OstreeRepo *remote_repo_local; - GPtrArray *localcache_repos; /* Array */ - - GMainContext *main_context; - GCancellable *cancellable; - OstreeAsyncProgress *progress; - - GVariant *extra_headers; - char *append_user_agent; - - gboolean dry_run; - gboolean dry_run_emitted_progress; - gboolean legacy_transaction_resuming; - guint n_network_retries; - enum { - OSTREE_PULL_PHASE_FETCHING_REFS, - OSTREE_PULL_PHASE_FETCHING_OBJECTS - } phase; - gint n_scanned_metadata; - - gboolean gpg_verify; - gboolean gpg_verify_summary; - gboolean require_static_deltas; - gboolean disable_static_deltas; - gboolean has_tombstone_commits; - - GBytes *summary_data; - GBytes *summary_data_sig; - GVariant *summary; - GHashTable *summary_deltas_checksums; - GHashTable *ref_original_commits; /* Maps checksum to commit, used by timestamp checks */ - GHashTable *verified_commits; /* Set of commits that have been verified */ - GHashTable *ref_keyring_map; /* Maps OstreeCollectionRef to keyring remote name */ - GPtrArray *static_delta_superblocks; - GHashTable *expected_commit_sizes; /* Maps commit checksum to known size */ - GHashTable *commit_to_depth; /* Maps commit checksum maximum depth */ - GHashTable *scanned_metadata; /* Maps object name to itself */ - GHashTable *fetched_detached_metadata; /* Map */ - GHashTable *requested_metadata; /* Maps object name to itself */ - GHashTable *requested_content; /* Maps checksum to itself */ - GHashTable *requested_fallback_content; /* Maps checksum to itself */ - GHashTable *pending_fetch_metadata; /* Map */ - GHashTable *pending_fetch_content; /* Map */ - GHashTable *pending_fetch_delta_superblocks; /* Set */ - GHashTable *pending_fetch_deltaparts; /* Set */ - guint n_outstanding_metadata_fetches; - guint n_outstanding_metadata_write_requests; - guint n_outstanding_content_fetches; - guint n_outstanding_content_write_requests; - guint n_outstanding_deltapart_fetches; - guint n_outstanding_deltapart_write_requests; - guint n_total_deltaparts; - guint n_total_delta_fallbacks; - guint64 fetched_deltapart_size; /* How much of the delta we have now */ - guint64 total_deltapart_size; - guint64 total_deltapart_usize; - gint n_requested_metadata; - gint n_requested_content; - guint n_fetched_deltaparts; - guint n_fetched_deltapart_fallbacks; - guint n_fetched_metadata; - guint n_fetched_content; - /* Objects imported via hardlink/reflink/copying or --localcache-repo*/ - guint n_imported_metadata; - guint n_imported_content; - - gboolean timestamp_check; /* Verify commit timestamps */ - int maxdepth; - guint64 max_metadata_size; - guint64 start_time; - - gboolean is_mirror; - gboolean trusted_http_direct; - gboolean is_commit_only; - OstreeRepoImportFlags importflags; - - GPtrArray *dirs; - - gboolean have_previous_bytes; - guint64 previous_bytes_sec; - guint64 previous_total_downloaded; - - GError *cached_async_error; - GError **async_error; - gboolean caught_error; - - GQueue scan_object_queue; - GSource *idle_src; -} OtPullData; - typedef struct { OtPullData *pull_data; GVariant *object; @@ -260,14 +148,6 @@ static gboolean scan_one_metadata_object (OtPullData *pull_data, GCancellable *cancellable, GError **error); static void scan_object_queue_data_free (ScanObjectQueueData *scan_data); -static gboolean -ostree_verify_unwritten_commit (OtPullData *pull_data, - const char *checksum, - GVariant *commit, - GVariant *detached_metadata, - const OstreeCollectionRef *ref, - GCancellable *cancellable, - GError **error); static gboolean update_progress (gpointer user_data) @@ -1119,7 +999,10 @@ content_fetch_on_complete (GObject *object, if (!ostree_content_stream_parse (TRUE, tmpf_input, stbuf.st_size, FALSE, &file_in, &file_info, &xattrs, cancellable, error)) - goto out; + { + g_prefix_error (error, "Parsing %s: ", checksum_obj); + goto out; + } if (verifying_bareuseronly) { @@ -1309,8 +1192,8 @@ meta_fetch_on_complete (GObject *object, * metadata into this hash. */ GVariant *detached_data = g_hash_table_lookup (pull_data->fetched_detached_metadata, checksum); - if (!ostree_verify_unwritten_commit (pull_data, checksum, metadata, detached_data, - fetch_data->requested_ref, pull_data->cancellable, error)) + if (!_verify_unwritten_commit (pull_data, checksum, metadata, detached_data, + fetch_data->requested_ref, pull_data->cancellable, error)) goto out; if (!ostree_repo_mark_commit_partial (pull_data->repo, checksum, TRUE, error)) @@ -1434,75 +1317,6 @@ static_deltapart_fetch_on_complete (GObject *object, g_clear_pointer (&fetch_data, fetch_static_delta_data_free); } -#ifndef OSTREE_DISABLE_GPGME -static gboolean -process_verify_result (OtPullData *pull_data, - const char *checksum, - OstreeGpgVerifyResult *result, - GError **error) -{ - const char *error_prefix = glnx_strjoina ("Commit ", checksum); - GLNX_AUTO_PREFIX_ERROR(error_prefix, error); - if (result == NULL) - return FALSE; - - /* Allow callers to output the results immediately. */ - g_signal_emit_by_name (pull_data->repo, - "gpg-verify-result", - checksum, result); - - if (!ostree_gpg_verify_result_require_valid_signature (result, error)) - return FALSE; - - - /* We now check both *before* writing the commit, and after. Because the - * behavior used to be only verifiying after writing, we need to handle - * the case of "written but not verified". But we also don't want to check - * twice, as that'd result in duplicate signals. - */ - g_hash_table_add (pull_data->verified_commits, g_strdup (checksum)); - - return TRUE; -} -#endif /* OSTREE_DISABLE_GPGME */ - -static gboolean -ostree_verify_unwritten_commit (OtPullData *pull_data, - const char *checksum, - GVariant *commit, - GVariant *detached_metadata, - const OstreeCollectionRef *ref, - GCancellable *cancellable, - GError **error) -{ -#ifndef OSTREE_DISABLE_GPGME - if (pull_data->gpg_verify) - { - const char *keyring_remote = NULL; - - /* Shouldn't happen, but see comment in process_verify_result() */ - if (g_hash_table_contains (pull_data->verified_commits, checksum)) - return TRUE; - - if (ref != NULL) - keyring_remote = g_hash_table_lookup (pull_data->ref_keyring_map, ref); - if (keyring_remote == NULL) - keyring_remote = pull_data->remote_name; - - g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes (commit); - g_autoptr(OstreeGpgVerifyResult) result = - _ostree_repo_gpg_verify_with_metadata (pull_data->repo, signed_data, - detached_metadata, - keyring_remote, - NULL, NULL, cancellable, error); - if (!process_verify_result (pull_data, checksum, result, error)) - return FALSE; - } -#endif /* OSTREE_DISABLE_GPGME */ - - return TRUE; -} - static gboolean commitstate_is_partial (OtPullData *pull_data, OstreeRepoCommitState commitstate) @@ -1513,109 +1327,6 @@ commitstate_is_partial (OtPullData *pull_data, #endif /* HAVE_LIBCURL_OR_LIBSOUP */ -/** - * _ostree_repo_verify_bindings: - * @collection_id: (nullable): Locally specified collection ID for the remote - * the @commit was retrieved from, or %NULL if none is configured - * @ref_name: (nullable): Ref name the commit was retrieved using, or %NULL if - * the commit was retrieved by checksum - * @commit: Commit data to check - * @error: Return location for a #GError, or %NULL - * - * Verify the ref and collection bindings. - * - * The ref binding is verified only if it exists. But if we have the - * collection ID specified in the remote configuration (@collection_id is - * non-%NULL) then the ref binding must exist, otherwise the verification will - * fail. Parts of the verification can be skipped by passing %NULL to the - * @ref_name parameter (in case we requested a checksum directly, without - * looking it up from a ref). - * - * The collection binding is verified only when we have collection ID - * specified in the remote configuration. If it is specified, then the - * binding must exist and must be equal to the remote repository - * collection ID. - * - * Returns: %TRUE if bindings are correct, %FALSE otherwise - * Since: 2017.14 - */ -gboolean -_ostree_repo_verify_bindings (const char *collection_id, - const char *ref_name, - GVariant *commit, - GError **error) -{ - g_autoptr(GVariant) metadata = g_variant_get_child_value (commit, 0); - g_autofree const char **refs = NULL; - if (!g_variant_lookup (metadata, - OSTREE_COMMIT_META_KEY_REF_BINDING, - "^a&s", - &refs)) - { - /* Early return here - if the remote collection ID is NULL, then - * we certainly will not verify the collection binding in the - * commit. - */ - if (collection_id == NULL) - return TRUE; - - return glnx_throw (error, - "Expected commit metadata to have ref " - "binding information, found none"); - } - - if (ref_name != NULL) - { - if (!g_strv_contains ((const char *const *) refs, ref_name)) - { - g_autoptr(GString) refs_dump = g_string_new (NULL); - const char *refs_str; - - if (refs != NULL && (*refs) != NULL) - { - for (const char **iter = refs; *iter != NULL; ++iter) - { - const char *ref = *iter; - - if (refs_dump->len > 0) - g_string_append (refs_dump, ", "); - g_string_append_printf (refs_dump, "‘%s’", ref); - } - - refs_str = refs_dump->str; - } - else - { - refs_str = "no refs"; - } - - return glnx_throw (error, "Commit has no requested ref ‘%s’ " - "in ref binding metadata (%s)", - ref_name, refs_str); - } - } - - if (collection_id != NULL) - { - const char *collection_id_binding; - if (!g_variant_lookup (metadata, - OSTREE_COMMIT_META_KEY_COLLECTION_BINDING, - "&s", - &collection_id_binding)) - return glnx_throw (error, - "Expected commit metadata to have collection ID " - "binding information, found none"); - if (!g_str_equal (collection_id_binding, collection_id)) - return glnx_throw (error, - "Commit has collection ID ‘%s’ in collection binding " - "metadata, while the remote it came from has " - "collection ID ‘%s’", - collection_id_binding, collection_id); - } - - return TRUE; -} - /* Reads the collection-id of a given remote from the repo * configuration. */ @@ -1824,11 +1535,51 @@ scan_commit_object (OtPullData *pull_data, keyring_remote, cancellable, error); - if (!process_verify_result (pull_data, checksum, result, error)) + if (!_process_gpg_verify_result (pull_data, checksum, result, error)) return FALSE; } #endif /* OSTREE_DISABLE_GPGME */ + if (pull_data->signapi_commit_verifiers && + !g_hash_table_contains (pull_data->signapi_verified_commits, checksum)) + { + g_autoptr(GError) last_verification_error = NULL; + gboolean found_any_signature = FALSE; + gboolean found_valid_signature = FALSE; + g_autofree char *success_message = NULL; + + for (guint i = 0; i < pull_data->signapi_commit_verifiers->len; i++) + { + OstreeSign *sign = pull_data->signapi_commit_verifiers->pdata[i]; + + found_any_signature = TRUE; + + /* Set return to true if any sign fit */ + if (ostree_sign_commit_verify (sign, + pull_data->repo, + checksum, + &success_message, + cancellable, + last_verification_error ? NULL : &last_verification_error)) + { + found_valid_signature = TRUE; + break; + } + } + + if (!found_any_signature) + return glnx_throw (error, "No signatures found for commit %s", checksum); + + if (!found_valid_signature) + { + g_assert (last_verification_error); + g_propagate_error (error, g_steal_pointer (&last_verification_error)); + return glnx_prefix_error (error, "Can't verify commit %s", checksum); + } + g_assert (success_message); + g_hash_table_insert (pull_data->signapi_verified_commits, g_strdup (checksum), g_steal_pointer (&success_message)); + } + /* If we found a legacy transaction flag, assume we have to scan. * We always do a scan of dirtree objects; see * https://github.com/ostreedev/ostree/issues/543 @@ -1848,6 +1599,7 @@ scan_commit_object (OtPullData *pull_data, commit, error)) return glnx_prefix_error (error, "Commit %s", checksum); + guint64 new_ts = ostree_commit_get_timestamp (commit); if (pull_data->timestamp_check) { /* We don't support timestamp checking while recursing right now */ @@ -1866,11 +1618,22 @@ scan_commit_object (OtPullData *pull_data, return glnx_prefix_error (error, "Reading %s for timestamp-check", ref->ref_name); guint64 orig_ts = ostree_commit_get_timestamp (orig_commit); - guint64 new_ts = ostree_commit_get_timestamp (commit); if (!_ostree_compare_timestamps (orig_rev, orig_ts, checksum, new_ts, error)) return FALSE; } } + if (pull_data->timestamp_check_from_rev) + { + g_autoptr(GVariant) commit = NULL; + if (!ostree_repo_load_commit (pull_data->repo, pull_data->timestamp_check_from_rev, + &commit, NULL, error)) + return glnx_prefix_error (error, "Reading %s for timestamp-check-from-rev", + pull_data->timestamp_check_from_rev); + + guint64 ts = ostree_commit_get_timestamp (commit); + if (!_ostree_compare_timestamps (pull_data->timestamp_check_from_rev, ts, checksum, new_ts, error)) + return FALSE; + } /* If we found a legacy transaction flag, assume all commits are partial */ gboolean is_partial = commitstate_is_partial (pull_data, commitstate); @@ -2413,8 +2176,8 @@ process_one_static_delta (OtPullData *pull_data, g_autofree char *detached_path = _ostree_get_relative_static_delta_path (from_revision, to_revision, "commitmeta"); g_autoptr(GVariant) detached_data = g_variant_lookup_value (metadata, detached_path, G_VARIANT_TYPE("a{sv}")); - if (!ostree_verify_unwritten_commit (pull_data, to_revision, to_commit, detached_data, - ref, cancellable, error)) + if (!_verify_unwritten_commit (pull_data, to_revision, to_commit, detached_data, + ref, cancellable, error)) return FALSE; if (detached_data && !ostree_repo_write_commit_detached_metadata (pull_data->repo, @@ -3520,11 +3283,15 @@ initiate_request (OtPullData *pull_data, * * override-remote-name (s): If local, add this remote to refspec * * gpg-verify (b): GPG verify commits * * gpg-verify-summary (b): GPG verify summary + * * disable-sign-verify (b): Disable signapi verification of commits + * * disable-sign-verify-summary (b): Disable signapi verification of the summary * * depth (i): How far in the history to traverse; default is 0, -1 means infinite + * * per-object-fsync (b): Perform disk writes more slowly, avoiding a single large I/O sync * * disable-static-deltas (b): Do not use static deltas * * require-static-deltas (b): Require static deltas * * override-commit-ids (as): Array of specific commit IDs to fetch for refs * * timestamp-check (b): Verify commit timestamps are newer than current (when pulling via ref); Since: 2017.11 + * * timestamp-check-from-rev (s): Verify that all fetched commit timestamps are newer than timestamp of given rev; Since: 2020.4 * * metadata-size-restriction (t): Restrict metadata objects to a maximum number of bytes; 0 to disable. Since: 2018.9 * * dry-run (b): Only print information on what will be downloaded (requires static deltas) * * override-url (s): Fetch objects from this URL if remote specifies no metalink in options @@ -3574,11 +3341,14 @@ ostree_repo_pull_with_options (OstreeRepo *self, g_autoptr(GVariantIter) collection_refs_iter = NULL; g_autofree char **override_commit_ids = NULL; g_autoptr(GSource) update_timeout = NULL; + gboolean opt_per_object_fsync = FALSE; gboolean opt_gpg_verify_set = FALSE; gboolean opt_gpg_verify_summary_set = FALSE; gboolean opt_collection_refs_set = FALSE; gboolean opt_n_network_retries_set = FALSE; gboolean opt_ref_keyring_map_set = FALSE; + gboolean disable_sign_verify = FALSE; + gboolean disable_sign_verify_summary = FALSE; const char *main_collection_id = NULL; const char *url_override = NULL; gboolean inherit_transaction = FALSE; @@ -3590,6 +3360,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, * value, otherwise NULL. Used for logging. */ const char *the_ref_to_fetch = NULL; + OstreeRepoTransactionStats tstats = { 0, }; /* Default */ pull_data->max_metadata_size = OSTREE_MAX_METADATA_SIZE; @@ -3610,17 +3381,21 @@ ostree_repo_pull_with_options (OstreeRepo *self, g_variant_lookup (options, "gpg-verify", "b", &pull_data->gpg_verify); opt_gpg_verify_summary_set = g_variant_lookup (options, "gpg-verify-summary", "b", &pull_data->gpg_verify_summary); + g_variant_lookup (options, "disable-sign-verify", "b", &disable_sign_verify); + g_variant_lookup (options, "disable-sign-verify-summary", "b", &disable_sign_verify_summary); (void) g_variant_lookup (options, "depth", "i", &pull_data->maxdepth); (void) g_variant_lookup (options, "disable-static-deltas", "b", &pull_data->disable_static_deltas); (void) g_variant_lookup (options, "require-static-deltas", "b", &pull_data->require_static_deltas); (void) g_variant_lookup (options, "override-commit-ids", "^a&s", &override_commit_ids); (void) g_variant_lookup (options, "dry-run", "b", &pull_data->dry_run); + (void) g_variant_lookup (options, "per-object-fsync", "b", &opt_per_object_fsync); (void) g_variant_lookup (options, "override-url", "&s", &url_override); (void) g_variant_lookup (options, "inherit-transaction", "b", &inherit_transaction); (void) g_variant_lookup (options, "http-headers", "@a(ss)", &pull_data->extra_headers); (void) g_variant_lookup (options, "update-frequency", "u", &update_frequency); (void) g_variant_lookup (options, "localcache-repos", "^a&s", &opt_localcache_repos); (void) g_variant_lookup (options, "timestamp-check", "b", &pull_data->timestamp_check); + (void) g_variant_lookup (options, "timestamp-check-from-rev", "s", &pull_data->timestamp_check_from_rev); (void) g_variant_lookup (options, "max-metadata-size", "t", &pull_data->max_metadata_size); (void) g_variant_lookup (options, "append-user-agent", "s", &pull_data->append_user_agent); opt_n_network_retries_set = @@ -3634,10 +3409,10 @@ ostree_repo_pull_with_options (OstreeRepo *self, #ifdef OSTREE_DISABLE_GPGME /* Explicitly fail here if gpg verification is requested and we have no GPG support */ - if (opt_gpg_verify_set || opt_gpg_verify_summary_set) + if (pull_data->gpg_verify || pull_data->gpg_verify_summary) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "'%s': GPG feature is disabled in a build time", + "'%s': GPG feature is disabled at build time", __FUNCTION__); goto out; } @@ -3682,6 +3457,10 @@ ostree_repo_pull_with_options (OstreeRepo *self, pull_data->main_context = g_main_context_ref_thread_default (); pull_data->flags = flags; + /* TODO: Avoid mutating the repo object */ + if (opt_per_object_fsync) + self->per_object_fsync = TRUE; + if (!opt_n_network_retries_set) pull_data->n_network_retries = DEFAULT_N_NETWORK_RETRIES; @@ -3702,6 +3481,8 @@ ostree_repo_pull_with_options (OstreeRepo *self, (GDestroyNotify)g_free); pull_data->verified_commits = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL); + pull_data->signapi_verified_commits = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify)g_free, NULL); pull_data->ref_keyring_map = g_hash_table_new_full (ostree_collection_ref_hash, ostree_collection_ref_equal, (GDestroyNotify)ostree_collection_ref_free, (GDestroyNotify)g_free); pull_data->scanned_metadata = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, @@ -3759,7 +3540,9 @@ ostree_repo_pull_with_options (OstreeRepo *self, /* For compatibility with pull-local, don't gpg verify local * pulls by default. */ - if ((pull_data->gpg_verify || pull_data->gpg_verify_summary) && + if ((pull_data->gpg_verify || + pull_data->gpg_verify_summary + ) && pull_data->remote_name == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, @@ -3774,7 +3557,6 @@ ostree_repo_pull_with_options (OstreeRepo *self, g_free (pull_data->remote_name); pull_data->remote_name = g_strdup (remote_name_or_baseurl); -#ifndef OSTREE_DISABLE_GPGME /* Fetch GPG verification settings from remote if it wasn't already * explicitly set in the options. */ if (!opt_gpg_verify_set) @@ -3786,7 +3568,6 @@ ostree_repo_pull_with_options (OstreeRepo *self, if (!ostree_repo_remote_get_gpg_verify_summary (self, pull_data->remote_name, &pull_data->gpg_verify_summary, error)) goto out; -#endif /* OSTREE_DISABLE_GPGME */ /* NOTE: If changing this, see the matching implementation in * ostree-sysroot-upgrader.c @@ -3805,6 +3586,15 @@ ostree_repo_pull_with_options (OstreeRepo *self, } } + if (pull_data->remote_name && !(disable_sign_verify && disable_sign_verify_summary)) + { + if (!_signapi_init_for_remote (pull_data->repo, pull_data->remote_name, + &pull_data->signapi_commit_verifiers, + &pull_data->signapi_summary_verifiers, + error)) + return FALSE; + } + pull_data->phase = OSTREE_PULL_PHASE_FETCHING_REFS; if (!reinitialize_fetcher (pull_data, remote_name_or_baseurl, error)) @@ -4168,6 +3958,65 @@ ostree_repo_pull_with_options (OstreeRepo *self, } #endif /* OSTREE_DISABLE_GPGME */ + if (pull_data->signapi_summary_verifiers) + { + if (!bytes_sig && pull_data->signapi_summary_verifiers) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Signatures verification enabled, but no summary.sig found (use sign-verify-summary=false in remote config to disable)"); + goto out; + } + if (bytes_summary && bytes_sig) + { + g_autoptr(GVariant) signatures = NULL; + g_autoptr(GError) temp_error = NULL; + + signatures = g_variant_new_from_bytes (OSTREE_SUMMARY_SIG_GVARIANT_FORMAT, + bytes_sig, FALSE); + + + g_assert (pull_data->signapi_summary_verifiers); + if (!_sign_verify_for_remote (pull_data->signapi_summary_verifiers, bytes_summary, signatures, NULL, &temp_error)) + { + if (summary_from_cache) + { + /* The cached summary doesn't match, fetch a new one and verify again */ + if ((self->test_error_flags & OSTREE_REPO_TEST_ERROR_INVALID_CACHE) > 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Remote %s cached summary invalid and " + "OSTREE_REPO_TEST_ERROR_INVALID_CACHE specified", + pull_data->remote_name); + goto out; + } + else + g_debug ("Remote %s cached summary invalid, pulling new version", + pull_data->remote_name); + + summary_from_cache = FALSE; + g_clear_pointer (&bytes_summary, (GDestroyNotify)g_bytes_unref); + if (!_ostree_fetcher_mirrored_request_to_membuf (pull_data->fetcher, + pull_data->meta_mirrorlist, + "summary", + OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT, + pull_data->n_network_retries, + &bytes_summary, + OSTREE_MAX_METADATA_SIZE, + cancellable, error)) + goto out; + + if (!_sign_verify_for_remote (pull_data->signapi_summary_verifiers, bytes_summary, signatures, NULL, error)) + goto out; + } + else + { + g_propagate_error (error, g_steal_pointer (&temp_error)); + goto out; + } + } + } + } + if (bytes_summary) { pull_data->summary_data = g_bytes_ref (bytes_summary); @@ -4427,6 +4276,18 @@ ostree_repo_pull_with_options (OstreeRepo *self, g_steal_pointer (&checksum)); } + /* Resolve refs to a checksum if necessary */ + if (pull_data->timestamp_check_from_rev && + !ostree_validate_checksum_string (pull_data->timestamp_check_from_rev, NULL)) + { + g_autofree char *from_rev = NULL; + if (!ostree_repo_resolve_rev (pull_data->repo, pull_data->timestamp_check_from_rev, FALSE, + &from_rev, error)) + goto out; + g_free (pull_data->timestamp_check_from_rev); + pull_data->timestamp_check_from_rev = g_steal_pointer (&from_rev); + } + g_hash_table_unref (requested_refs_to_fetch); requested_refs_to_fetch = g_steal_pointer (&updated_requested_refs_to_fetch); if (g_hash_table_size (requested_refs_to_fetch) == 1) @@ -4567,7 +4428,8 @@ ostree_repo_pull_with_options (OstreeRepo *self, } } - if (pull_data->is_mirror && pull_data->summary_data && !refs_to_fetch && !configured_branches) + if (pull_data->is_mirror && pull_data->summary_data && + !refs_to_fetch && !opt_collection_refs_set && !configured_branches) { GLnxFileReplaceFlags replaceflag = pull_data->repo->disable_fsync ? GLNX_FILE_REPLACE_NODATASYNC : 0; @@ -4590,7 +4452,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, } if (!inherit_transaction && - !ostree_repo_commit_transaction (pull_data->repo, NULL, cancellable, error)) + !ostree_repo_commit_transaction (pull_data->repo, &tstats, cancellable, error)) goto out; end_time = g_get_monotonic_time (); @@ -4632,6 +4494,11 @@ ostree_repo_pull_with_options (OstreeRepo *self, shift == 1 ? "B" : "KiB", (guint) ((end_time - pull_data->start_time) / G_USEC_PER_SEC)); } + if (!inherit_transaction) + { + g_autofree char *bytes_written = g_format_size (tstats.content_bytes_written); + g_string_append_printf (buf, "; %s content written", bytes_written); + } ostree_async_progress_set_status (pull_data->progress, buf->str); } @@ -4647,22 +4514,26 @@ ostree_repo_pull_with_options (OstreeRepo *self, g_string_append_printf (msg, "libostree pull from '%s' for %u refs complete", pull_data->remote_name, g_hash_table_size (requested_refs_to_fetch)); - const char *verify_state; + const char *gpg_verify_state; #ifndef OSTREE_DISABLE_GPGME if (pull_data->gpg_verify_summary) { if (pull_data->gpg_verify) - verify_state = "summary+commit"; + gpg_verify_state = "summary+commit"; else - verify_state = "summary-only"; + gpg_verify_state = "summary-only"; } else - verify_state = (pull_data->gpg_verify ? "commit" : "disabled"); - g_string_append_printf (msg, "\nsecurity: GPG: %s ", verify_state); + gpg_verify_state = (pull_data->gpg_verify ? "commit" : "disabled"); + #else - verify_state = "disabled"; - g_string_append_printf (msg, "\nsecurity: %s ", verify_state); + gpg_verify_state = "disabled"; #endif /* OSTREE_DISABLE_GPGME */ + g_string_append_printf (msg, "\nsecurity: GPG: %s ", gpg_verify_state); + + const char *sign_verify_state; + sign_verify_state = (pull_data->signapi_commit_verifiers ? "commit" : "disabled"); + g_string_append_printf (msg, "\nsecurity: SIGN: %s ", sign_verify_state); OstreeFetcherURI *first_uri = pull_data->meta_mirrorlist->pdata[0]; g_autofree char *first_scheme = _ostree_fetcher_uri_get_scheme (first_uri); @@ -4694,11 +4565,16 @@ ostree_repo_pull_with_options (OstreeRepo *self, const guint n_seconds = (guint) ((end_time - pull_data->start_time) / G_USEC_PER_SEC); g_autofree char *formatted_xferred = g_format_size (bytes_transferred); g_string_append_printf (msg, "\ntransfer: secs: %u size: %s", n_seconds, formatted_xferred); + if (pull_data->signapi_commit_verifiers) + { + g_assert_cmpuint (g_hash_table_size (pull_data->signapi_verified_commits), >, 0); + } ot_journal_send ("MESSAGE=%s", msg->str, "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(OSTREE_MESSAGE_FETCH_COMPLETE_ID), "OSTREE_REMOTE=%s", pull_data->remote_name, - "OSTREE_GPG=%s", verify_state, + "OSTREE_SIGN=%s", sign_verify_state, + "OSTREE_GPG=%s", gpg_verify_state, "OSTREE_SECONDS=%u", n_seconds, "OSTREE_XFER_SIZE=%s", formatted_xferred, NULL); @@ -4719,6 +4595,13 @@ ostree_repo_pull_with_options (OstreeRepo *self, if (!ostree_repo_mark_commit_partial (pull_data->repo, commit, FALSE, error)) goto out; } + + /* and finally any parent commits we might also have pulled because of depth>0 */ + GLNX_HASH_TABLE_FOREACH (pull_data->commit_to_depth, const char*, commit) + { + if (!ostree_repo_mark_commit_partial (pull_data->repo, commit, FALSE, error)) + goto out; + } } ret = TRUE; @@ -4746,6 +4629,8 @@ ostree_repo_pull_with_options (OstreeRepo *self, g_free (pull_data->remote_refspec_name); g_free (pull_data->remote_name); g_free (pull_data->append_user_agent); + g_clear_pointer (&pull_data->signapi_commit_verifiers, (GDestroyNotify) g_ptr_array_unref); + g_clear_pointer (&pull_data->signapi_summary_verifiers, (GDestroyNotify) g_ptr_array_unref); g_clear_pointer (&pull_data->meta_mirrorlist, (GDestroyNotify) g_ptr_array_unref); g_clear_pointer (&pull_data->content_mirrorlist, (GDestroyNotify) g_ptr_array_unref); g_clear_pointer (&pull_data->summary_data, (GDestroyNotify) g_bytes_unref); @@ -4758,7 +4643,9 @@ ostree_repo_pull_with_options (OstreeRepo *self, g_clear_pointer (&pull_data->fetched_detached_metadata, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->summary_deltas_checksums, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->ref_original_commits, (GDestroyNotify) g_hash_table_unref); + g_free (pull_data->timestamp_check_from_rev); g_clear_pointer (&pull_data->verified_commits, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->signapi_verified_commits, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->ref_keyring_map, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->requested_content, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->requested_fallback_content, (GDestroyNotify) g_hash_table_unref); @@ -6016,6 +5903,8 @@ ostree_repo_pull_from_remotes_async (OstreeRepo *self, g_variant_dict_insert (&local_options_dict, "gpg-verify", "b", FALSE); #endif /* OSTREE_DISABLE_GPGME */ g_variant_dict_insert (&local_options_dict, "gpg-verify-summary", "b", FALSE); + g_variant_dict_insert (&local_options_dict, "sign-verify", "b", FALSE); + g_variant_dict_insert (&local_options_dict, "sign-verify-summary", "b", FALSE); g_variant_dict_insert (&local_options_dict, "inherit-transaction", "b", TRUE); if (result->remote->refspec_name != NULL) g_variant_dict_insert (&local_options_dict, "override-remote-name", "s", result->remote->refspec_name); @@ -6162,9 +6051,8 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self, g_autofree char *metalink_url_string = NULL; g_autoptr(GBytes) summary = NULL; g_autoptr(GBytes) signatures = NULL; -#ifndef OSTREE_DISABLE_GPGME gboolean gpg_verify_summary; -#endif + g_autoptr(GPtrArray) signapi_summary_verifiers = NULL; gboolean ret = FALSE; gboolean summary_is_from_cache; @@ -6186,37 +6074,73 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self, error)) goto out; -#ifndef OSTREE_DISABLE_GPGME if (!ostree_repo_remote_get_gpg_verify_summary (self, name, &gpg_verify_summary, error)) goto out; - if (gpg_verify_summary && summary == NULL) + if (gpg_verify_summary) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "GPG verification enabled, but no summary found (check that the configured URL in remote config is correct)"); - goto out; + if (summary == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "GPG verification enabled, but no summary found (check that the configured URL in remote config is correct)"); + goto out; + } + + if (signatures == NULL) + { + g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE, + "GPG verification enabled, but no summary signatures found (use gpg-verify-summary=false in remote config to disable)"); + goto out; + } + + /* Verify any summary signatures. */ + if (summary != NULL && signatures != NULL) + { + g_autoptr(OstreeGpgVerifyResult) result = NULL; + + result = ostree_repo_verify_summary (self, + name, + summary, + signatures, + cancellable, + error); + if (!ostree_gpg_verify_result_require_valid_signature (result, error)) + goto out; + } } - if (gpg_verify_summary && signatures == NULL) - { - g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE, - "GPG verification enabled, but no summary signatures found (use gpg-verify-summary=false in remote config to disable)"); - goto out; - } + if (!_signapi_init_for_remote (self, name, NULL, + &signapi_summary_verifiers, + error)) + goto out; - /* Verify any summary signatures. */ - if (gpg_verify_summary && summary != NULL && signatures != NULL) + if (signapi_summary_verifiers) { - g_autoptr(OstreeGpgVerifyResult) result = NULL; + if (summary == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Signature verification enabled, but no summary found (check that the configured URL in remote config is correct)"); + goto out; + } - result = ostree_repo_verify_summary (self, - name, - summary, - signatures, - cancellable, - error); - if (!ostree_gpg_verify_result_require_valid_signature (result, error)) - goto out; + if (signatures == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Signature verification enabled, but no summary signatures found (use sign-verify-summary=false in remote config to disable)"); + goto out; + } + + /* Verify any summary signatures. */ + if (summary != NULL && signatures != NULL) + { + g_autoptr(GVariant) sig_variant = NULL; + + sig_variant = g_variant_new_from_bytes (OSTREE_SUMMARY_SIG_GVARIANT_FORMAT, + signatures, FALSE); + + if (!_sign_verify_for_remote (signapi_summary_verifiers, summary, sig_variant, NULL, error)) + goto out; + } } if (!summary_is_from_cache && summary && signatures) @@ -6240,10 +6164,6 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self, } } -#else - g_message ("%s: GPG feature is disabled in a build time", __FUNCTION__); -#endif /* OSTREE_DISABLE_GPGME */ - if (out_summary != NULL) *out_summary = g_steal_pointer (&summary); diff --git a/src/libostree/ostree-repo-static-delta-compilation.c b/src/libostree/ostree-repo-static-delta-compilation.c index 88e9ddf6..3e9a8e30 100644 --- a/src/libostree/ostree-repo-static-delta-compilation.c +++ b/src/libostree/ostree-repo-static-delta-compilation.c @@ -1346,7 +1346,6 @@ ostree_repo_static_delta_generate (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; OstreeStaticDeltaBuilder builder = { 0, }; guint i; guint min_fallback_size; @@ -1365,8 +1364,8 @@ ostree_repo_static_delta_generate (OstreeRepo *self, g_autoptr(GVariant) detached = NULL; gboolean inline_parts; guint endianness = G_BYTE_ORDER; - builder.parts = g_ptr_array_new_with_free_func ((GDestroyNotify)ostree_static_delta_part_builder_unref); - builder.fallback_objects = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref); + g_autoptr(GPtrArray) builder_parts = g_ptr_array_new_with_free_func ((GDestroyNotify)ostree_static_delta_part_builder_unref); + g_autoptr(GPtrArray) builder_fallback_objects = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref); g_auto(GLnxTmpfile) descriptor_tmpf = { 0, }; g_autoptr(OtVariantBuilder) descriptor_builder = NULL; @@ -1385,6 +1384,8 @@ ostree_repo_static_delta_generate (OstreeRepo *self, g_return_val_if_fail (endianness == G_BIG_ENDIAN || endianness == G_LITTLE_ENDIAN, FALSE); builder.swap_endian = endianness != G_BYTE_ORDER; + builder.parts = builder_parts; + builder.fallback_objects = builder_fallback_objects; { gboolean use_bsdiff; if (!g_variant_lookup (params, "bsdiff-enabled", "b", &use_bsdiff)) @@ -1408,7 +1409,7 @@ ostree_repo_static_delta_generate (OstreeRepo *self, if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, to, &to_commit, error)) - goto out; + return FALSE; builder.delta_opts = delta_opts; @@ -1419,7 +1420,7 @@ ostree_repo_static_delta_generate (OstreeRepo *self, descriptor_name = g_strdup (glnx_basename (opt_filename)); if (!glnx_opendirat (AT_FDCWD, dn, TRUE, &descriptor_dfd, error)) - goto out; + return FALSE; } else { @@ -1428,9 +1429,9 @@ ostree_repo_static_delta_generate (OstreeRepo *self, const char *dn = dirname (dnbuf); if (!glnx_shutil_mkdir_p_at (self->repo_dir_fd, dn, DEFAULT_DIRECTORY_MODE, cancellable, error)) - goto out; + return FALSE; if (!glnx_opendirat (self->repo_dir_fd, dn, TRUE, &descriptor_dfd, error)) - goto out; + return FALSE; descriptor_name = g_strdup (basename (descriptor_relpath)); } @@ -1439,17 +1440,17 @@ ostree_repo_static_delta_generate (OstreeRepo *self, /* Ignore optimization flags */ if (!generate_delta_lowlatency (self, from, to, delta_opts, &builder, cancellable, error)) - goto out; + return FALSE; if (!glnx_open_tmpfile_linkable_at (descriptor_dfd, ".", O_WRONLY | O_CLOEXEC, &descriptor_tmpf, error)) - goto out; + return FALSE; descriptor_builder = ot_variant_builder_new (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT), descriptor_tmpf.fd); /* Open the metadata dict */ if (!ot_variant_builder_open (descriptor_builder, G_VARIANT_TYPE ("a{sv}"), error)) - goto out; + return FALSE; /* NOTE: Add user-supplied metadata first. This is used by at least * flatpak as a way to provide MIME content sniffing, since the @@ -1464,7 +1465,7 @@ ostree_repo_static_delta_generate (OstreeRepo *self, while ((item = g_variant_iter_next_value (&iter))) { if (!ot_variant_builder_add_value (descriptor_builder, item, error)) - goto out; + return FALSE; g_variant_unref (item); } } @@ -1483,7 +1484,7 @@ ostree_repo_static_delta_generate (OstreeRepo *self, g_assert_not_reached (); } if (!ot_variant_builder_add (descriptor_builder, error, "{sv}", "ostree.endianness", g_variant_new_byte (endianness_char))) - goto out; + return FALSE; } part_headers = g_variant_builder_new (G_VARIANT_TYPE ("a" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT)); @@ -1504,21 +1505,18 @@ ostree_repo_static_delta_generate (OstreeRepo *self, !ot_variant_builder_add_from_fd (descriptor_builder, G_VARIANT_TYPE ("(yay)"), part_builder->part_tmpf.fd, part_builder->compressed_size, error) || !ot_variant_builder_close (descriptor_builder, error) || !ot_variant_builder_close (descriptor_builder, error)) - goto out; + return FALSE; } else { g_autofree char *partstr = g_strdup_printf ("%u", i); if (fchmod (part_builder->part_tmpf.fd, 0644) < 0) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "fchmod"); if (!glnx_link_tmpfile_at (&part_builder->part_tmpf, GLNX_LINK_TMPFILE_REPLACE, descriptor_dfd, partstr, error)) - goto out; + return FALSE; } g_variant_builder_add_value (part_headers, part_builder->header); @@ -1529,21 +1527,21 @@ ostree_repo_static_delta_generate (OstreeRepo *self, if (!get_fallback_headers (self, &builder, &fallback_headers, cancellable, error)) - goto out; + return FALSE; if (!ostree_repo_read_commit_detached_metadata (self, to, &detached, cancellable, error)) - goto out; + return FALSE; if (detached) { g_autofree char *detached_key = _ostree_get_relative_static_delta_path (from, to, "commitmeta"); if (!ot_variant_builder_add (descriptor_builder, error, "{sv}", detached_key, detached)) - goto out; + return FALSE; } /* Close metadata dict */ if (!ot_variant_builder_close (descriptor_builder, error)) - goto out; + return FALSE; /* Generate OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT */ { @@ -1568,10 +1566,10 @@ ostree_repo_static_delta_generate (OstreeRepo *self, g_variant_builder_end (part_headers), error) || !ot_variant_builder_add_value (descriptor_builder, fallback_headers, error)) - goto out; + return FALSE; if (!ot_variant_builder_end (descriptor_builder, error)) - goto out; + return FALSE; g_date_time_unref (now); } @@ -1589,18 +1587,11 @@ ostree_repo_static_delta_generate (OstreeRepo *self, } if (fchmod (descriptor_tmpf.fd, 0644) < 0) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "fchmod"); if (!glnx_link_tmpfile_at (&descriptor_tmpf, GLNX_LINK_TMPFILE_REPLACE, descriptor_dfd, descriptor_name, error)) - goto out; + return FALSE; - ret = TRUE; - out: - g_clear_pointer (&builder.parts, g_ptr_array_unref); - g_clear_pointer (&builder.fallback_objects, g_ptr_array_unref); - return ret; + return TRUE; } diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 3aeecc5c..95eb0efc 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -2028,17 +2028,8 @@ ostree_repo_remote_get_gpg_verify (OstreeRepo *self, return TRUE; } -#ifndef OSTREE_DISABLE_GPGME return ostree_repo_get_remote_boolean_option (self, name, "gpg-verify", TRUE, out_gpg_verify, error); -#else - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "'%s': GPG feature is disabled in a build time", - __FUNCTION__); - if (out_gpg_verify != NULL) - *out_gpg_verify = FALSE; - return FALSE; -#endif /* OSTREE_DISABLE_GPGME */ } /** @@ -2060,17 +2051,8 @@ ostree_repo_remote_get_gpg_verify_summary (OstreeRepo *self, gboolean *out_gpg_verify_summary, GError **error) { -#ifndef OSTREE_DISABLE_GPGME return ostree_repo_get_remote_boolean_option (self, name, "gpg-verify-summary", FALSE, out_gpg_verify_summary, error); -#else - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "'%s': GPG feature is disabled in a build time", - __FUNCTION__); - if (out_gpg_verify_summary != NULL) - *out_gpg_verify_summary = FALSE; - return FALSE; -#endif /* OSTREE_DISABLE_GPGME */ } /** @@ -2344,10 +2326,7 @@ out: return ret; #else /* OSTREE_DISABLE_GPGME */ - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "'%s': GPG feature is disabled in a build time", - __FUNCTION__); - return FALSE; + return glnx_throw (error, "GPG feature is disabled in a build time"); #endif /* OSTREE_DISABLE_GPGME */ } @@ -2943,6 +2922,10 @@ reload_core_config (OstreeRepo *self, ostree_repo_set_disable_fsync (self, TRUE); } + if (!ot_keyfile_get_boolean_with_default (self->config, "core", "per-object-fsync", + FALSE, &self->per_object_fsync, error)) + return FALSE; + /* See https://github.com/ostreedev/ostree/issues/758 */ if (!ot_keyfile_get_boolean_with_default (self->config, "core", "disable-xattrs", FALSE, &self->disable_xattrs, error)) @@ -3257,6 +3240,8 @@ ostree_repo_open (OstreeRepo *self, GCancellable *cancellable, GError **error) { + GLNX_AUTO_PREFIX_ERROR ("opening repo", error); + struct stat stbuf; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); @@ -3291,10 +3276,7 @@ ostree_repo_open (OstreeRepo *self, g_assert (self->repodir); if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->repodir), TRUE, &self->repo_dir_fd, error)) - { - g_prefix_error (error, "%s: ", gs_file_get_path_cached (self->repodir)); - return FALSE; - } + return FALSE; } if (!glnx_fstat (self->repo_dir_fd, &stbuf, error)) @@ -4992,10 +4974,7 @@ ostree_repo_append_gpg_signature (OstreeRepo *self, return TRUE; #else - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "'%s': GPG feature is disabled in a build time", - __FUNCTION__); - return FALSE; + return glnx_throw (error, "GPG feature is disabled in a build time"); #endif /* OSTREE_DISABLE_GPGME */ } @@ -5147,7 +5126,7 @@ ostree_repo_sign_commit (OstreeRepo *self, return TRUE; #else /* FIXME: Return false until refactoring */ - return FALSE; + return glnx_throw (error, "GPG feature is disabled in a build time"); #endif /* OSTREE_DISABLE_GPGME */ } @@ -5239,10 +5218,7 @@ ostree_repo_add_gpg_signature_summary (OstreeRepo *self, return TRUE; #else - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "'%s': GPG feature is disabled in a build time", - __FUNCTION__); - return FALSE; + return glnx_throw (error, "GPG feature is disabled in a build time"); #endif /* OSTREE_DISABLE_GPGME */ } @@ -5516,10 +5492,7 @@ ostree_repo_verify_commit (OstreeRepo *self, return TRUE; #else /* FIXME: Return false until refactoring */ - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "'%s': GPG feature is disabled in a build time", - __FUNCTION__); - return FALSE; + return glnx_throw (error, "GPG feature is disabled in a build time"); #endif /* OSTREE_DISABLE_GPGME */ } @@ -5554,9 +5527,7 @@ ostree_repo_verify_commit_ext (OstreeRepo *self, cancellable, error); #else - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "'%s': GPG feature is disabled in a build time", - __FUNCTION__); + glnx_throw (error, "GPG feature is disabled in a build time"); return NULL; #endif /* OSTREE_DISABLE_GPGME */ } @@ -5593,9 +5564,7 @@ ostree_repo_verify_commit_for_remote (OstreeRepo *self, cancellable, error); #else - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "'%s': GPG feature is disabled in a build time", - __FUNCTION__); + glnx_throw (error, "GPG feature is disabled in a build time"); return NULL; #endif /* OSTREE_DISABLE_GPGME */ } @@ -5645,9 +5614,7 @@ ostree_repo_gpg_verify_data (OstreeRepo *self, cancellable, error); #else - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "'%s': GPG feature is disabled in a build time", - __FUNCTION__); + glnx_throw (error, "GPG feature is disabled in a build time"); return NULL; #endif /* OSTREE_DISABLE_GPGME */ } @@ -5693,9 +5660,7 @@ ostree_repo_verify_summary (OstreeRepo *self, cancellable, error); #else - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "'%s': GPG feature is disabled in a build time", - __FUNCTION__); + glnx_throw (error, "GPG feature is disabled in a build time"); return NULL; #endif /* OSTREE_DISABLE_GPGME */ } @@ -5998,7 +5963,7 @@ _ostree_repo_maybe_regenerate_summary (OstreeRepo *self, } gboolean -_ostree_repo_is_locked_tmpdir (const char *filename) +_ostree_repo_has_staging_prefix (const char *filename) { return g_str_has_prefix (filename, OSTREE_REPO_TMPDIR_STAGING); } @@ -6019,7 +5984,9 @@ _ostree_repo_try_lock_tmpdir (int tmpdir_dfd, if (!glnx_make_lock_file (tmpdir_dfd, lock_name, LOCK_EX | LOCK_NB, file_lock_out, &local_error)) { - if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) + /* we need to handle EACCES too in the case of POSIX locks; see F_SETLK in fcntl(2) */ + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) + || g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED)) { did_lock = FALSE; } @@ -6058,7 +6025,7 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd, GCancellable *cancellable, GError **error) { - g_return_val_if_fail (_ostree_repo_is_locked_tmpdir (tmpdir_prefix), FALSE); + g_return_val_if_fail (_ostree_repo_has_staging_prefix (tmpdir_prefix), FALSE); /* Look for existing tmpdir (with same prefix) to reuse */ g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; @@ -6280,3 +6247,107 @@ ostree_repo_get_bootloader (OstreeRepo *self) return self->bootloader; } + + +/** + * _ostree_repo_verify_bindings: + * @collection_id: (nullable): Locally specified collection ID for the remote + * the @commit was retrieved from, or %NULL if none is configured + * @ref_name: (nullable): Ref name the commit was retrieved using, or %NULL if + * the commit was retrieved by checksum + * @commit: Commit data to check + * @error: Return location for a #GError, or %NULL + * + * Verify the ref and collection bindings. + * + * The ref binding is verified only if it exists. But if we have the + * collection ID specified in the remote configuration (@collection_id is + * non-%NULL) then the ref binding must exist, otherwise the verification will + * fail. Parts of the verification can be skipped by passing %NULL to the + * @ref_name parameter (in case we requested a checksum directly, without + * looking it up from a ref). + * + * The collection binding is verified only when we have collection ID + * specified in the remote configuration. If it is specified, then the + * binding must exist and must be equal to the remote repository + * collection ID. + * + * Returns: %TRUE if bindings are correct, %FALSE otherwise + * Since: 2017.14 + */ +gboolean +_ostree_repo_verify_bindings (const char *collection_id, + const char *ref_name, + GVariant *commit, + GError **error) +{ + g_autoptr(GVariant) metadata = g_variant_get_child_value (commit, 0); + g_autofree const char **refs = NULL; + if (!g_variant_lookup (metadata, + OSTREE_COMMIT_META_KEY_REF_BINDING, + "^a&s", + &refs)) + { + /* Early return here - if the remote collection ID is NULL, then + * we certainly will not verify the collection binding in the + * commit. + */ + if (collection_id == NULL) + return TRUE; + + return glnx_throw (error, + "Expected commit metadata to have ref " + "binding information, found none"); + } + + if (ref_name != NULL) + { + if (!g_strv_contains ((const char *const *) refs, ref_name)) + { + g_autoptr(GString) refs_dump = g_string_new (NULL); + const char *refs_str; + + if (refs != NULL && (*refs) != NULL) + { + for (const char **iter = refs; *iter != NULL; ++iter) + { + const char *ref = *iter; + + if (refs_dump->len > 0) + g_string_append (refs_dump, ", "); + g_string_append_printf (refs_dump, "‘%s’", ref); + } + + refs_str = refs_dump->str; + } + else + { + refs_str = "no refs"; + } + + return glnx_throw (error, "Commit has no requested ref ‘%s’ " + "in ref binding metadata (%s)", + ref_name, refs_str); + } + } + + if (collection_id != NULL) + { + const char *collection_id_binding; + if (!g_variant_lookup (metadata, + OSTREE_COMMIT_META_KEY_COLLECTION_BINDING, + "&s", + &collection_id_binding)) + return glnx_throw (error, + "Expected commit metadata to have collection ID " + "binding information, found none"); + if (!g_str_equal (collection_id_binding, collection_id)) + return glnx_throw (error, + "Commit has collection ID ‘%s’ in collection binding " + "metadata, while the remote it came from has " + "collection ID ‘%s’", + collection_id_binding, collection_id); + } + + return TRUE; +} diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index 40d3f773..e28af29c 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -691,6 +691,13 @@ _OSTREE_PUBLIC void ostree_repo_commit_modifier_set_sepolicy (OstreeRepoCommitModifier *modifier, OstreeSePolicy *sepolicy); +_OSTREE_PUBLIC +gboolean ostree_repo_commit_modifier_set_sepolicy_from_commit (OstreeRepoCommitModifier *modifier, + OstreeRepo *repo, + const char *rev, + GCancellable *cancellable, + GError **error); + _OSTREE_PUBLIC void ostree_repo_commit_modifier_set_devino_cache (OstreeRepoCommitModifier *modifier, OstreeRepoDevInoCache *cache); @@ -1167,9 +1174,9 @@ void ostree_repo_commit_traverse_iter_cleanup (void *p); * @OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY: Do not traverse individual commit objects, only follow refs */ typedef enum { - OSTREE_REPO_PRUNE_FLAGS_NONE, - OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE, - OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY + OSTREE_REPO_PRUNE_FLAGS_NONE = 0, + OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE = (1 << 0), + OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY = (1 << 1), } OstreeRepoPruneFlags; _OSTREE_PUBLIC diff --git a/src/libostree/ostree-sign-dummy.c b/src/libostree/ostree-sign-dummy.c new file mode 100644 index 00000000..56f10d6e --- /dev/null +++ b/src/libostree/ostree-sign-dummy.c @@ -0,0 +1,196 @@ +/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */ + +/* + * Copyright © 2019 Collabora Ltd. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include +#include "ostree-sign-dummy.h" +#include + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "OSTreeSign" + +#define OSTREE_SIGN_DUMMY_NAME "dummy" + +#define OSTREE_SIGN_METADATA_DUMMY_KEY "ostree.sign.dummy" +#define OSTREE_SIGN_METADATA_DUMMY_TYPE "aay" + +struct _OstreeSignDummy +{ + GObject parent; + gchar *sk_ascii; + gchar *pk_ascii; +}; + +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSignDummy, g_object_unref) +#endif + +static void +ostree_sign_dummy_iface_init (OstreeSignInterface *self); + +G_DEFINE_TYPE_WITH_CODE (OstreeSignDummy, _ostree_sign_dummy, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (OSTREE_TYPE_SIGN, ostree_sign_dummy_iface_init)); + +static gboolean +check_dummy_sign_enabled (GError **error) +{ + if (g_strcmp0 (g_getenv ("OSTREE_DUMMY_SIGN_ENABLED"), "1") != 0) + return glnx_throw (error, "dummy signature type is only for ostree testing"); + return TRUE; +} + +static void +ostree_sign_dummy_iface_init (OstreeSignInterface *self) +{ + + self->get_name = ostree_sign_dummy_get_name; + self->data = ostree_sign_dummy_data; + self->data_verify = ostree_sign_dummy_data_verify; + self->metadata_key = ostree_sign_dummy_metadata_key; + self->metadata_format = ostree_sign_dummy_metadata_format; + self->set_sk = ostree_sign_dummy_set_sk; + self->set_pk = ostree_sign_dummy_set_pk; + /* Implementation for dummy engine just load the single public key */ + self->add_pk = ostree_sign_dummy_set_pk; +} + +static void +_ostree_sign_dummy_class_init (OstreeSignDummyClass *self) +{ +} + +static void +_ostree_sign_dummy_init (OstreeSignDummy *self) +{ + + self->sk_ascii = NULL; + self->pk_ascii = NULL; +} + +gboolean ostree_sign_dummy_set_sk (OstreeSign *self, GVariant *key, GError **error) +{ + if (!check_dummy_sign_enabled (error)) + return FALSE; + + OstreeSignDummy *sign = _ostree_sign_dummy_get_instance_private(OSTREE_SIGN_DUMMY(self)); + + g_free(sign->sk_ascii); + + sign->sk_ascii = g_variant_dup_string (key, 0); + + return TRUE; +} + +gboolean ostree_sign_dummy_set_pk (OstreeSign *self, GVariant *key, GError **error) +{ + OstreeSignDummy *sign = _ostree_sign_dummy_get_instance_private(OSTREE_SIGN_DUMMY(self)); + + g_free(sign->pk_ascii); + + sign->pk_ascii = g_variant_dup_string (key, 0); + + return TRUE; +} + +gboolean ostree_sign_dummy_data (OstreeSign *self, + GBytes *data, + GBytes **signature, + GCancellable *cancellable, + GError **error) +{ + if (!check_dummy_sign_enabled (error)) + return FALSE; + + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + OstreeSignDummy *sign = _ostree_sign_dummy_get_instance_private(OSTREE_SIGN_DUMMY(self)); + + *signature = g_bytes_new (sign->sk_ascii, strlen(sign->sk_ascii)); + + return TRUE; +} + +const gchar * ostree_sign_dummy_get_name (OstreeSign *self) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + return OSTREE_SIGN_DUMMY_NAME; +} + +const gchar * ostree_sign_dummy_metadata_key (OstreeSign *self) +{ + + return OSTREE_SIGN_METADATA_DUMMY_KEY; +} + +const gchar * ostree_sign_dummy_metadata_format (OstreeSign *self) +{ + + return OSTREE_SIGN_METADATA_DUMMY_TYPE; +} + +gboolean ostree_sign_dummy_data_verify (OstreeSign *self, + GBytes *data, + GVariant *signatures, + char **out_success_message, + GError **error) +{ + if (!check_dummy_sign_enabled (error)) + return FALSE; + + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + g_return_val_if_fail (data != NULL, FALSE); + + OstreeSignDummy *sign = _ostree_sign_dummy_get_instance_private(OSTREE_SIGN_DUMMY(self)); + + if (signatures == NULL) + return glnx_throw (error, "signature: dummy: commit have no signatures of my type"); + + if (!g_variant_is_of_type (signatures, (GVariantType *) OSTREE_SIGN_METADATA_DUMMY_TYPE)) + return glnx_throw (error, "signature: dummy: wrong type passed for verification"); + + for (gsize i = 0; i < g_variant_n_children(signatures); i++) + { + g_autoptr (GVariant) child = g_variant_get_child_value (signatures, i); + g_autoptr (GBytes) signature = g_variant_get_data_as_bytes(child); + + gsize sign_size = 0; + g_bytes_get_data (signature, &sign_size); + g_autofree gchar *sign_ascii = g_strndup(g_bytes_get_data (signature, NULL), sign_size); + g_debug("Read signature %d: %s", (gint)i, sign_ascii); + g_debug("Stored signature %d: %s", (gint)i, sign->pk_ascii); + + if (!g_strcmp0(sign_ascii, sign->pk_ascii)) + { + if (out_success_message) + *out_success_message = g_strdup ("dummy: Signature verified"); + return TRUE; + } + else + return glnx_throw (error, "signature: dummy: incorrect signature %" G_GSIZE_FORMAT, i); + } + + return glnx_throw (error, "signature: dummy: no signatures"); +} diff --git a/src/libostree/ostree-sign-dummy.h b/src/libostree/ostree-sign-dummy.h new file mode 100644 index 00000000..bf5d63a1 --- /dev/null +++ b/src/libostree/ostree-sign-dummy.h @@ -0,0 +1,77 @@ +/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */ + +/* + * Copyright © 2019 Collabora Ltd. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Denis Pynkin (d4s) + */ + +#pragma once + +#include "ostree-sign.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_SIGN_DUMMY (_ostree_sign_dummy_get_type ()) + +GType _ostree_sign_dummy_get_type (void); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +typedef struct _OstreeSignDummy OstreeSignDummy; +typedef struct { GObjectClass parent_class; } OstreeSignDummyClass; + +static inline OstreeSignDummy *OSTREE_SIGN_DUMMY (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, _ostree_sign_dummy_get_type (), OstreeSignDummy); } +static inline gboolean OSTREE_IS_SIGN_DUMMY (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, _ostree_sign_dummy_get_type ()); } + +G_GNUC_END_IGNORE_DEPRECATIONS + +/* Have to use glib-2.44 for this +_OSTREE_PUBLIC +G_DECLARE_FINAL_TYPE (OstreeSignDummy, + ostree_sign_dummy, + OSTREE, + SIGN_DUMMY, + GObject) +*/ + +const gchar * ostree_sign_dummy_get_name (OstreeSign *self); + +gboolean ostree_sign_dummy_data (OstreeSign *self, + GBytes *data, + GBytes **signature, + GCancellable *cancellable, + GError **error); + +gboolean ostree_sign_dummy_data_verify (OstreeSign *self, + GBytes *data, + GVariant *signatures, + char **success_message, + GError **error); + +const gchar * ostree_sign_dummy_metadata_key (OstreeSign *self); +const gchar * ostree_sign_dummy_metadata_format (OstreeSign *self); + +gboolean ostree_sign_dummy_set_sk (OstreeSign *self, GVariant *key, GError **error); +gboolean ostree_sign_dummy_set_pk (OstreeSign *self, GVariant *key, GError **error); +gboolean ostree_sign_dummy_add_pk (OstreeSign *self, GVariant *key, GError **error); + +G_END_DECLS + diff --git a/src/libostree/ostree-sign-ed25519.c b/src/libostree/ostree-sign-ed25519.c new file mode 100644 index 00000000..d728afde --- /dev/null +++ b/src/libostree/ostree-sign-ed25519.c @@ -0,0 +1,672 @@ +/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */ +/* + * Copyright © 2019 Collabora Ltd. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Denis Pynkin (d4s) + */ + +#include "config.h" + +#include +#include "ostree-sign-ed25519.h" +#ifdef HAVE_LIBSODIUM +#include +#endif + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "OSTreeSign" + +#define OSTREE_SIGN_ED25519_NAME "ed25519" + +#define OSTREE_SIGN_METADATA_ED25519_KEY "ostree.sign.ed25519" +#define OSTREE_SIGN_METADATA_ED25519_TYPE "aay" + +typedef enum +{ + ED25519_OK, + ED25519_NOT_SUPPORTED, + ED25519_FAILED_INITIALIZATION +} ed25519_state; + +struct _OstreeSignEd25519 +{ + GObject parent; + ed25519_state state; + guchar *secret_key; + GList *public_keys; + GList *revoked_keys; +}; + +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSignEd25519, g_object_unref) +#endif + +static void +ostree_sign_ed25519_iface_init (OstreeSignInterface *self); + +G_DEFINE_TYPE_WITH_CODE (OstreeSignEd25519, _ostree_sign_ed25519, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (OSTREE_TYPE_SIGN, ostree_sign_ed25519_iface_init)); + +static void +ostree_sign_ed25519_iface_init (OstreeSignInterface *self) +{ + + self->data = ostree_sign_ed25519_data; + self->data_verify = ostree_sign_ed25519_data_verify; + self->get_name = ostree_sign_ed25519_get_name; + self->metadata_key = ostree_sign_ed25519_metadata_key; + self->metadata_format = ostree_sign_ed25519_metadata_format; + self->clear_keys = ostree_sign_ed25519_clear_keys; + self->set_sk = ostree_sign_ed25519_set_sk; + self->set_pk = ostree_sign_ed25519_set_pk; + self->add_pk = ostree_sign_ed25519_add_pk; + self->load_pk = ostree_sign_ed25519_load_pk; +} + +static void +_ostree_sign_ed25519_class_init (OstreeSignEd25519Class *self) +{ +} + +static void +_ostree_sign_ed25519_init (OstreeSignEd25519 *self) +{ + + self->state = ED25519_OK; + self->secret_key = NULL; + self->public_keys = NULL; + self->revoked_keys = NULL; + +#ifdef HAVE_LIBSODIUM + if (sodium_init() < 0) + self->state = ED25519_FAILED_INITIALIZATION; +#else + self->state = ED25519_NOT_SUPPORTED; +#endif /* HAVE_LIBSODIUM */ +} + +static gboolean +_ostree_sign_ed25519_is_initialized (OstreeSignEd25519 *self, GError **error) +{ + switch (self->state) + { + case ED25519_OK: + break; + case ED25519_NOT_SUPPORTED: + return glnx_throw(error, "ed25519: engine is not supported"); + case ED25519_FAILED_INITIALIZATION: + return glnx_throw(error, "ed25519: libsodium library isn't initialized properly"); + } + + return TRUE; +} + +gboolean ostree_sign_ed25519_data (OstreeSign *self, + GBytes *data, + GBytes **signature, + GCancellable *cancellable, + GError **error) +{ + + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self)); + +#ifdef HAVE_LIBSODIUM + guchar *sig = NULL; +#endif + + if (!_ostree_sign_ed25519_is_initialized (sign, error)) + return FALSE; + + if (sign->secret_key == NULL) + return glnx_throw (error, "Not able to sign: secret key is not set"); + +#ifdef HAVE_LIBSODIUM + unsigned long long sig_size = 0; + + sig = g_malloc0(crypto_sign_BYTES); + + if (crypto_sign_detached (sig, + &sig_size, + g_bytes_get_data (data, NULL), + g_bytes_get_size (data), + sign->secret_key)) + { + return glnx_throw (error, "Not able to sign: fail to sign the object"); + } + + *signature = g_bytes_new_take (sig, sig_size); + return TRUE; +#endif /* HAVE_LIBSODIUM */ + return FALSE; +} + +#ifdef HAVE_LIBSODIUM +static gint +_compare_ed25519_keys(gconstpointer a, gconstpointer b) { + return memcmp (a, b, crypto_sign_PUBLICKEYBYTES); +} +#endif + +gboolean ostree_sign_ed25519_data_verify (OstreeSign *self, + GBytes *data, + GVariant *signatures, + char **out_success_message, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + g_return_val_if_fail (data != NULL, FALSE); + + OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self)); + + if (!_ostree_sign_ed25519_is_initialized (sign, error)) + return FALSE; + + if (signatures == NULL) + return glnx_throw (error, "ed25519: commit have no signatures of my type"); + + if (!g_variant_is_of_type (signatures, (GVariantType *) OSTREE_SIGN_METADATA_ED25519_TYPE)) + return glnx_throw (error, "ed25519: wrong type passed for verification"); + +#ifdef HAVE_LIBSODIUM + /* If no keys pre-loaded then, + * try to load public keys from storage(s) */ + if (sign->public_keys == NULL) + { + g_autoptr (GVariantBuilder) builder = NULL; + g_autoptr (GVariant) options = NULL; + + builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + options = g_variant_builder_end (builder); + + if (!ostree_sign_ed25519_load_pk (self, options, error)) + return FALSE; + } + + g_debug ("verify: data hash = 0x%x", g_bytes_hash(data)); + + g_autoptr(GString) invalid_signatures = NULL; + guint n_invalid_signatures = 0; + + for (gsize i = 0; i < g_variant_n_children(signatures); i++) + { + g_autoptr (GVariant) child = g_variant_get_child_value (signatures, i); + g_autoptr (GBytes) signature = g_variant_get_data_as_bytes(child); + + g_autofree char * hex = g_malloc0 (crypto_sign_PUBLICKEYBYTES*2 + 1); + + g_debug("Read signature %d: %s", (gint)i, g_variant_print(child, TRUE)); + + for (GList *public_key = sign->public_keys; + public_key != NULL; + public_key = public_key->next) + { + + /* TODO: use non-list for tons of revoked keys? */ + if (g_list_find_custom (sign->revoked_keys, public_key->data, _compare_ed25519_keys) != NULL) + { + g_debug("Skip revoked key '%s'", + sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, public_key->data, crypto_sign_PUBLICKEYBYTES)); + continue; + } + + if (crypto_sign_verify_detached ((guchar *) g_variant_get_data (child), + g_bytes_get_data (data, NULL), + g_bytes_get_size (data), + public_key->data) != 0) + { + /* Incorrect signature! */ + if (invalid_signatures == NULL) + invalid_signatures = g_string_new (""); + else + g_string_append (invalid_signatures, "; "); + n_invalid_signatures++; + g_string_append_printf (invalid_signatures, "key '%s'", + sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, public_key->data, crypto_sign_PUBLICKEYBYTES)); + } + else + { + if (out_success_message) + { + *out_success_message = + g_strdup_printf ("ed25519: Signature verified successfully with key '%s'", + sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, public_key->data, crypto_sign_PUBLICKEYBYTES)); + } + return TRUE; + } + } + } + + if (invalid_signatures) + { + g_assert_cmpuint (n_invalid_signatures, >, 0); + /* The test suite has a key ring with 100 keys. This seems insane, let's + * cap a reasonable error message at 3. + */ + if (n_invalid_signatures > 3) + return glnx_throw (error, "ed25519: Signature couldn't be verified; tried %u keys", n_invalid_signatures); + return glnx_throw (error, "ed25519: Signature couldn't be verified with: %s", invalid_signatures->str); + } + return glnx_throw (error, "ed25519: no signatures found"); +#endif /* HAVE_LIBSODIUM */ + + return FALSE; +} + +const gchar * ostree_sign_ed25519_get_name (OstreeSign *self) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + return OSTREE_SIGN_ED25519_NAME; +} + +const gchar * ostree_sign_ed25519_metadata_key (OstreeSign *self) +{ + + return OSTREE_SIGN_METADATA_ED25519_KEY; +} + +const gchar * ostree_sign_ed25519_metadata_format (OstreeSign *self) +{ + + return OSTREE_SIGN_METADATA_ED25519_TYPE; +} + +gboolean ostree_sign_ed25519_clear_keys (OstreeSign *self, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self)); + + if (!_ostree_sign_ed25519_is_initialized (sign, error)) + return FALSE; + +#ifdef HAVE_LIBSODIUM + /* Clear secret key */ + if (sign->secret_key != NULL) + { + memset (sign->secret_key, 0, crypto_sign_SECRETKEYBYTES); + g_free (sign->secret_key); + sign->secret_key = NULL; + } + + /* Clear already loaded trusted keys */ + if (sign->public_keys != NULL) + { + g_list_free_full (sign->public_keys, g_free); + sign->public_keys = NULL; + } + + /* Clear already loaded revoked keys */ + if (sign->revoked_keys != NULL) + { + g_list_free_full (sign->revoked_keys, g_free); + sign->revoked_keys = NULL; + } + + return TRUE; +#endif /* HAVE_LIBSODIUM */ + + return FALSE; +} + +/* Support 2 representations: + * base64 ascii -- secret key is passed as string + * raw key -- key is passed as bytes array + * */ +gboolean ostree_sign_ed25519_set_sk (OstreeSign *self, + GVariant *secret_key, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + + if (!ostree_sign_ed25519_clear_keys (self, error)) + return FALSE; + +#ifdef HAVE_LIBSODIUM + OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self)); + + gsize n_elements = 0; + + if (g_variant_is_of_type (secret_key, G_VARIANT_TYPE_STRING)) + { + const gchar *sk_ascii = g_variant_get_string (secret_key, NULL); + sign->secret_key = g_base64_decode (sk_ascii, &n_elements); + } + else if (g_variant_is_of_type (secret_key, G_VARIANT_TYPE_BYTESTRING)) + { + sign->secret_key = (guchar *) g_variant_get_fixed_array (secret_key, &n_elements, sizeof(guchar)); + } + else + { + return glnx_throw (error, "Unknown ed25519 secret key type"); + } + + if (n_elements != crypto_sign_SECRETKEYBYTES) + return glnx_throw (error, "Incorrect ed25519 secret key"); + + return TRUE; +#endif /* HAVE_LIBSODIUM */ + + return FALSE; +} + +/* Support 2 representations: + * base64 ascii -- public key is passed as string + * raw key -- key is passed as bytes array + * */ +gboolean ostree_sign_ed25519_set_pk (OstreeSign *self, + GVariant *public_key, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + if (!ostree_sign_ed25519_clear_keys (self, error)) + return FALSE; + + return ostree_sign_ed25519_add_pk (self, public_key, error); +} + +/* Support 2 representations: + * base64 ascii -- public key is passed as string + * raw key -- key is passed as bytes array + * */ +gboolean ostree_sign_ed25519_add_pk (OstreeSign *self, + GVariant *public_key, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self)); + + if (!_ostree_sign_ed25519_is_initialized (sign, error)) + return FALSE; + +#ifdef HAVE_LIBSODIUM + gpointer key = NULL; + gsize n_elements = 0; + + if (g_variant_is_of_type (public_key, G_VARIANT_TYPE_STRING)) + { + const gchar *pk_ascii = g_variant_get_string (public_key, NULL); + key = g_base64_decode (pk_ascii, &n_elements); + } + else if (g_variant_is_of_type (public_key, G_VARIANT_TYPE_BYTESTRING)) + { + key = (gpointer) g_variant_get_fixed_array (public_key, &n_elements, sizeof(guchar)); + } + else + { + return glnx_throw (error, "Unknown ed25519 public key type"); + } + + if (n_elements != crypto_sign_PUBLICKEYBYTES) + return glnx_throw (error, "Incorrect ed25519 public key"); + + g_autofree char *hex = g_malloc0 (crypto_sign_PUBLICKEYBYTES*2 + 1); + g_debug ("Read ed25519 public key = %s", sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, key, n_elements)); + + if (g_list_find_custom (sign->public_keys, key, _compare_ed25519_keys) == NULL) + { + gpointer newkey = g_memdup (key, n_elements); + sign->public_keys = g_list_prepend (sign->public_keys, newkey); + } + +#endif /* HAVE_LIBSODIUM */ + return TRUE; +} + +#ifdef HAVE_LIBSODIUM +/* Add revoked public key */ +static gboolean +_ed25519_add_revoked (OstreeSign *self, + GVariant *revoked_key, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + if (!g_variant_is_of_type (revoked_key, G_VARIANT_TYPE_STRING)) + return glnx_throw (error, "Unknown ed25519 revoked key type"); + + OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self)); + + const gchar *rk_ascii = g_variant_get_string (revoked_key, NULL); + gsize n_elements = 0; + gpointer key = g_base64_decode (rk_ascii, &n_elements); + + if (n_elements != crypto_sign_PUBLICKEYBYTES) + { + return glnx_throw (error, "Incorrect ed25519 revoked key"); + } + + g_autofree char * hex = g_malloc0 (crypto_sign_PUBLICKEYBYTES*2 + 1); + g_debug ("Read ed25519 revoked key = %s", sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, key, n_elements)); + + if (g_list_find_custom (sign->revoked_keys, key, _compare_ed25519_keys) == NULL) + { + gpointer newkey = g_memdup (key, n_elements); + sign->revoked_keys = g_list_prepend (sign->revoked_keys, newkey); + } + + return TRUE; +} +#endif /* HAVE_LIBSODIUM */ + + +static gboolean +_load_pk_from_stream (OstreeSign *self, + GDataInputStream *key_data_in, + gboolean trusted, + GError **error) +{ + g_return_val_if_fail (key_data_in, FALSE); +#ifdef HAVE_LIBSODIUM + gboolean ret = FALSE; + + /* Use simple file format with just a list of base64 public keys per line */ + while (TRUE) + { + gsize len = 0; + g_autofree char *line = g_data_input_stream_read_line (key_data_in, &len, NULL, error); + g_autoptr (GVariant) pk = NULL; + gboolean added = FALSE; + + if (*error != NULL) + return FALSE; + + if (line == NULL) + return ret; + + /* Read the key itself */ + /* base64 encoded key */ + pk = g_variant_new_string (line); + + if (trusted) + added = ostree_sign_ed25519_add_pk (self, pk, error); + else + added = _ed25519_add_revoked (self, pk, error); + + g_debug ("%s %s key: %s", + added ? "Added" : "Invalid", + trusted ? "public" : "revoked", + line); + + /* Mark what we load at least one key */ + if (added) + ret = TRUE; + } +#endif /* HAVE_LIBSODIUM */ + return FALSE; +} + +static gboolean +_load_pk_from_file (OstreeSign *self, + const gchar *filename, + gboolean trusted, + GError **error) +{ + g_debug ("Processing file '%s'", filename); + + g_autoptr (GFile) keyfile = NULL; + g_autoptr (GFileInputStream) key_stream_in = NULL; + g_autoptr (GDataInputStream) key_data_in = NULL; + + if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) + { + g_debug ("Can't open file '%s' with public keys", filename); + return glnx_throw (error, "File object '%s' is not a regular file", filename); + } + + keyfile = g_file_new_for_path (filename); + key_stream_in = g_file_read (keyfile, NULL, error); + if (key_stream_in == NULL) + return FALSE; + + key_data_in = g_data_input_stream_new (G_INPUT_STREAM(key_stream_in)); + g_assert (key_data_in != NULL); + + if (!_load_pk_from_stream (self, key_data_in, trusted, error)) + { + if (error == NULL || *error == NULL) + return glnx_throw (error, + "signature: ed25519: no valid keys in file '%s'", + filename); + else + return FALSE; + } + + return TRUE; +} + +static gboolean +_ed25519_load_pk (OstreeSign *self, + GVariant *options, + gboolean trusted, + GError **error) +{ + + gboolean ret = FALSE; + const gchar *custom_dir = NULL; + + g_autoptr (GPtrArray) base_dirs = g_ptr_array_new_with_free_func (g_free); + g_autoptr (GPtrArray) ed25519_files = g_ptr_array_new_with_free_func (g_free); + + if (g_variant_lookup (options, "basedir", "&s", &custom_dir)) + { + /* Add custom directory */ + g_ptr_array_add (base_dirs, g_strdup (custom_dir)); + } + else + { + /* Default paths where to find files with public keys */ + g_ptr_array_add (base_dirs, g_strdup ("/etc/ostree")); + g_ptr_array_add (base_dirs, g_strdup (DATADIR "/ostree")); + } + + /* Scan all well-known directories and construct the list with file names to scan keys */ + for (gint i=0; i < base_dirs->len; i++) + { + gchar *base_name = NULL; + g_autofree gchar *base_dir = NULL; + g_autoptr (GDir) dir = NULL; + + base_name = g_build_filename ((gchar *)g_ptr_array_index (base_dirs, i), + trusted ? "trusted.ed25519" : "revoked.ed25519", + NULL); + + g_debug ("Check ed25519 keys from file: %s", base_name); + g_ptr_array_add (ed25519_files, base_name); + + base_dir = g_strconcat (base_name, ".d", NULL); + dir = g_dir_open (base_dir, 0, error); + if (dir == NULL) + { + g_clear_error (error); + continue; + } + const gchar *entry = NULL; + while ((entry = g_dir_read_name (dir)) != NULL) + { + gchar *filename = g_build_filename (base_dir, entry, NULL); + g_debug ("Check ed25519 keys from file: %s", filename); + g_ptr_array_add (ed25519_files, filename); + } + } + + /* Scan all well-known files */ + for (gint i=0; i < ed25519_files->len; i++) + { + if (!_load_pk_from_file (self, (gchar *)g_ptr_array_index (ed25519_files, i), trusted, error)) + { + g_debug ("Problem with loading ed25519 %s keys from `%s`", + trusted ? "public" : "revoked", + (gchar *)g_ptr_array_index (ed25519_files, i)); + g_clear_error(error); + } + else + ret = TRUE; + } + + if (!ret && (error == NULL || *error == NULL)) + return glnx_throw (error, "signature: ed25519: no keys loaded"); + + return ret; +} + +/* + * options argument should be a{sv}: + * - filename -- single file to use to load keys from; + * - basedir -- directory containing subdirectories + * 'trusted.ed25519.d' and 'revoked.ed25519.d' with appropriate + * public keys. Used for testing and re-definition of system-wide + * directories if defaults are not suitable for any reason. + */ +gboolean +ostree_sign_ed25519_load_pk (OstreeSign *self, + GVariant *options, + GError **error) +{ + + const gchar *filename = NULL; + + OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self)); + if (!_ostree_sign_ed25519_is_initialized (sign, error)) + return FALSE; + + /* Read keys only from single file provided */ + if (g_variant_lookup (options, "filename", "&s", &filename)) + return _load_pk_from_file (self, filename, TRUE, error); + + /* Load public keys from well-known directories and files */ + if (!_ed25519_load_pk (self, options, TRUE, error)) + return FALSE; + + /* Load untrusted keys from well-known directories and files + * Ignore the failure from this function -- it is expected to have + * empty list of revoked keys. + * */ + if (!_ed25519_load_pk (self, options, FALSE, error)) + g_clear_error(error); + + return TRUE; +} diff --git a/src/libostree/ostree-sign-ed25519.h b/src/libostree/ostree-sign-ed25519.h new file mode 100644 index 00000000..72152eab --- /dev/null +++ b/src/libostree/ostree-sign-ed25519.h @@ -0,0 +1,91 @@ +/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */ + +/* + * Copyright © 2019 Collabora Ltd. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Denis Pynkin (d4s) + */ + +#pragma once + +#include "ostree-sign.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_SIGN_ED25519 (_ostree_sign_ed25519_get_type ()) + +GType _ostree_sign_ed25519_get_type (void); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +typedef struct _OstreeSignEd25519 OstreeSignEd25519; +typedef struct { GObjectClass parent_class; } OstreeSignEd25519Class; + +static inline OstreeSignEd25519 *OSTREE_SIGN_ED25519 (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, _ostree_sign_ed25519_get_type (), OstreeSignEd25519); } +static inline gboolean OSTREE_IS_SIGN_ED25519 (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, _ostree_sign_ed25519_get_type ()); } + +G_GNUC_END_IGNORE_DEPRECATIONS + +/* Have to use glib-2.44 for this +_OSTREE_PUBLIC +G_DECLARE_FINAL_TYPE (OstreeSignEd25519, + ostree_sign_ed25519, + OSTREE, + SIGN_ED25519, + GObject) +*/ + +gboolean ostree_sign_ed25519_data (OstreeSign *self, + GBytes *data, + GBytes **signature, + GCancellable *cancellable, + GError **error); + +gboolean ostree_sign_ed25519_data_verify (OstreeSign *self, + GBytes *data, + GVariant *signatures, + char **out_success_message, + GError **error); + +const gchar * ostree_sign_ed25519_get_name (OstreeSign *self); +const gchar * ostree_sign_ed25519_metadata_key (OstreeSign *self); +const gchar * ostree_sign_ed25519_metadata_format (OstreeSign *self); + +gboolean ostree_sign_ed25519_clear_keys (OstreeSign *self, + GError **error); + +gboolean ostree_sign_ed25519_set_sk (OstreeSign *self, + GVariant *secret_key, + GError **error); + +gboolean ostree_sign_ed25519_set_pk (OstreeSign *self, + GVariant *public_key, + GError **error); + +gboolean ostree_sign_ed25519_add_pk (OstreeSign *self, + GVariant *public_key, + GError **error); + +gboolean ostree_sign_ed25519_load_pk (OstreeSign *self, + GVariant *options, + GError **error); + +G_END_DECLS + diff --git a/src/libostree/ostree-sign.c b/src/libostree/ostree-sign.c new file mode 100644 index 00000000..bcb5d0a6 --- /dev/null +++ b/src/libostree/ostree-sign.c @@ -0,0 +1,668 @@ +/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */ + +/* + * Copyright © 2019 Collabora Ltd. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/** + * SECTION:ostree-sign + * @title: Signature management + * @short_description: Sign and verify commits + * + * An #OstreeSign interface allows to select and use any available engine + * for signing or verifying the commit object or summary file. + */ + +#include "config.h" + +#include +#include +#include +#include "libglnx.h" +#include "otutil.h" + +#include "ostree-autocleanups.h" +#include "ostree-core.h" +#include "ostree-sign.h" +#include "ostree-sign-dummy.h" +#ifdef HAVE_LIBSODIUM +#include "ostree-sign-ed25519.h" +#endif + +#include "ostree-autocleanups.h" +#include "ostree-repo-private.h" + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "OSTreeSign" + +typedef struct +{ + gchar *name; + GType type; +} _sign_type; + +_sign_type sign_types[] = +{ +#if defined(HAVE_LIBSODIUM) + {OSTREE_SIGN_NAME_ED25519, 0}, +#endif + {"dummy", 0} +}; + +enum +{ +#if defined(HAVE_LIBSODIUM) + SIGN_ED25519, +#endif + SIGN_DUMMY +}; + +G_DEFINE_INTERFACE (OstreeSign, ostree_sign, G_TYPE_OBJECT) + +static void +ostree_sign_default_init (OstreeSignInterface *iface) +{ + g_debug ("OstreeSign initialization"); +} + +/** + * ostree_sign_metadata_key: + * @self: an #OstreeSign object + * + * Return the pointer to the name of the key used in (detached) metadata for + * current signing engine. + * + * Returns: (transfer none): pointer to the metadata key name, + * @NULL in case of error (unlikely). + * + * Since: 2020.2 + */ +const gchar * +ostree_sign_metadata_key (OstreeSign *self) +{ + + g_return_val_if_fail (OSTREE_SIGN_GET_IFACE (self)->metadata_key != NULL, NULL); + return OSTREE_SIGN_GET_IFACE (self)->metadata_key (self); +} + +/** + * ostree_sign_metadata_format: + * @self: an #OstreeSign object + * + * Return the pointer to the string with format used in (detached) metadata for + * current signing engine. + * + * Returns: (transfer none): pointer to the metadata format, + * @NULL in case of error (unlikely). + * + * Since: 2020.2 + */ +const gchar * +ostree_sign_metadata_format (OstreeSign *self) +{ + + g_return_val_if_fail (OSTREE_SIGN_GET_IFACE (self)->metadata_format != NULL, NULL); + return OSTREE_SIGN_GET_IFACE (self)->metadata_format (self); +} + +/** + * ostree_sign_clear_keys: + * @self: an #OstreeSign object + * @error: a #GError + * + * Clear all previously preloaded secret and public keys. + * + * Returns: @TRUE in case if no errors, @FALSE in case of error + * + * Since: 2020.2 + */ +gboolean +ostree_sign_clear_keys (OstreeSign *self, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + if (OSTREE_SIGN_GET_IFACE (self)->clear_keys == NULL) + return glnx_throw (error, "not implemented"); + + return OSTREE_SIGN_GET_IFACE (self)->clear_keys (self, error); +} + +/** + * ostree_sign_set_sk: + * @self: an #OstreeSign object + * @secret_key: secret key to be added + * @error: a #GError + * + * Set the secret key to be used for signing data, commits and summary. + * + * The @secret_key argument depends of the particular engine implementation. + * + * Returns: @TRUE in case if the key could be set successfully, + * @FALSE in case of error (@error will contain the reason). + * + * Since: 2020.2 + */ +gboolean +ostree_sign_set_sk (OstreeSign *self, + GVariant *secret_key, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + if (OSTREE_SIGN_GET_IFACE (self)->set_sk == NULL) + return glnx_throw (error, "not implemented"); + + return OSTREE_SIGN_GET_IFACE (self)->set_sk (self, secret_key, error); +} + +/** + * ostree_sign_set_pk: + * @self: an #OstreeSign object + * @public_key: single public key to be added + * @error: a #GError + * + * Set the public key for verification. It is expected what all + * previously pre-loaded public keys will be dropped. + * + * The @public_key argument depends of the particular engine implementation. + * + * Returns: @TRUE in case if the key could be set successfully, + * @FALSE in case of error (@error will contain the reason). + * + * Since: 2020.2 + */ +gboolean +ostree_sign_set_pk (OstreeSign *self, + GVariant *public_key, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + if (OSTREE_SIGN_GET_IFACE (self)->set_pk == NULL) + return glnx_throw (error, "not implemented"); + + return OSTREE_SIGN_GET_IFACE (self)->set_pk (self, public_key, error); +} + +/** + * ostree_sign_add_pk: + * @self: an #OstreeSign object + * @public_key: single public key to be added + * @error: a #GError + * + * Add the public key for verification. Could be called multiple times for + * adding all needed keys to be used for verification. + * + * The @public_key argument depends of the particular engine implementation. + * + * Returns: @TRUE in case if the key could be added successfully, + * @FALSE in case of error (@error will contain the reason). + * + * Since: 2020.2 + */ +gboolean +ostree_sign_add_pk (OstreeSign *self, + GVariant *public_key, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + if (OSTREE_SIGN_GET_IFACE (self)->add_pk == NULL) + return glnx_throw (error, "not implemented"); + + return OSTREE_SIGN_GET_IFACE (self)->add_pk (self, public_key, error); +} + +/** + * ostree_sign_load_pk: + * @self: an #OstreeSign object + * @options: any options + * @error: a #GError + * + * Load public keys for verification from anywhere. + * It is expected that all keys would be added to already pre-loaded keys. + * + * The @options argument depends of the particular engine implementation. + * + * For example, @ed25515 engine could use following string-formatted options: + * - @filename -- single file to use to load keys from + * - @basedir -- directory containing subdirectories + * 'trusted.ed25519.d' and 'revoked.ed25519.d' with appropriate + * public keys. Used for testing and re-definition of system-wide + * directories if defaults are not suitable for any reason. + * + * Returns: @TRUE in case if at least one key could be load successfully, + * @FALSE in case of error (@error will contain the reason). + * + * Since: 2020.2 + */ +/* + * No need to have similar function for secret keys load -- it is expected + * what the signing software will load the secret key in it's own way. + */ +gboolean +ostree_sign_load_pk (OstreeSign *self, + GVariant *options, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + if (OSTREE_SIGN_GET_IFACE (self)->load_pk == NULL) + return glnx_throw (error, "not implemented"); + + return OSTREE_SIGN_GET_IFACE (self)->load_pk (self, options, error); +} + +/** + * ostree_sign_data: + * @self: an #OstreeSign object + * @data: the raw data to be signed with pre-loaded secret key + * @signature: in case of success will contain signature + * @cancellable: A #GCancellable + * @error: a #GError + * + * Sign the given @data with pre-loaded secret key. + * + * Depending of the signing engine used you will need to load + * the secret key with #ostree_sign_set_sk. + * + * Returns: @TRUE if @data has been signed successfully, + * @FALSE in case of error (@error will contain the reason). + * + * Since: 2020.2 + */ +gboolean +ostree_sign_data (OstreeSign *self, + GBytes *data, + GBytes **signature, + GCancellable *cancellable, + GError **error) +{ + + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + if (OSTREE_SIGN_GET_IFACE (self)->data == NULL) + return glnx_throw (error, "not implemented"); + + return OSTREE_SIGN_GET_IFACE (self)->data (self, data, signature, cancellable, error); +} + +/** + * ostree_sign_data_verify: + * @self: an #OstreeSign object + * @data: the raw data to check + * @signatures: the signatures to be checked + * @error: a #GError + * + * Verify given data against signatures with pre-loaded public keys. + * + * Depending of the signing engine used you will need to load + * the public key(s) with #ostree_sign_set_pk, #ostree_sign_add_pk + * or #ostree_sign_load_pk. + * + * Returns: @TRUE if @data has been signed at least with any single valid key, + * @FALSE in case of error or no valid keys are available (@error will contain the reason). + * + * Since: 2020.2 + */ +gboolean +ostree_sign_data_verify (OstreeSign *self, + GBytes *data, + GVariant *signatures, + char **out_success_message, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + if (OSTREE_SIGN_GET_IFACE (self)->data_verify == NULL) + return glnx_throw (error, "not implemented"); + + return OSTREE_SIGN_GET_IFACE (self)->data_verify(self, data, signatures, out_success_message, error); +} + +/* + * Adopted version of _ostree_detached_metadata_append_gpg_sig () + */ +static GVariant * +_sign_detached_metadata_append (OstreeSign *self, + GVariant *existing_metadata, + GBytes *signature_bytes) +{ + g_return_val_if_fail (signature_bytes != NULL, FALSE); + + GVariantDict metadata_dict; + g_autoptr(GVariant) signature_data = NULL; + g_autoptr(GVariantBuilder) signature_builder = NULL; + + g_variant_dict_init (&metadata_dict, existing_metadata); + + const gchar *signature_key = ostree_sign_metadata_key(self); + GVariantType *signature_format = (GVariantType *) ostree_sign_metadata_format(self); + + signature_data = g_variant_dict_lookup_value (&metadata_dict, + signature_key, + (GVariantType*)signature_format); + + /* signature_data may be NULL */ + signature_builder = ot_util_variant_builder_from_variant (signature_data, signature_format); + + g_variant_builder_add (signature_builder, "@ay", ot_gvariant_new_ay_bytes (signature_bytes)); + + g_variant_dict_insert_value (&metadata_dict, + signature_key, + g_variant_builder_end (signature_builder)); + + return g_variant_dict_end (&metadata_dict); +} + +/** + * ostree_sign_commit_verify: + * @self: an #OstreeSign object + * @repo: an #OsreeRepo object + * @commit_checksum: SHA256 of given commit to verify + * @cancellable: A #GCancellable + * @error: a #GError + * + * Verify if commit is signed with known key. + * + * Depending of the signing engine used you will need to load + * the public key(s) for verification with #ostree_sign_set_pk, + * #ostree_sign_add_pk and/or #ostree_sign_load_pk. + * + * Returns: @TRUE if commit has been verified successfully, + * @FALSE in case of error or no valid keys are available (@error will contain the reason). + * + * Since: 2020.2 + */ +gboolean +ostree_sign_commit_verify (OstreeSign *self, + OstreeRepo *repo, + const gchar *commit_checksum, + char **out_success_message, + GCancellable *cancellable, + GError **error) + +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + g_autoptr(GVariant) commit_variant = NULL; + /* Load the commit */ + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, + commit_checksum, &commit_variant, + error)) + return glnx_prefix_error (error, "Failed to read commit"); + + /* Load the metadata */ + g_autoptr(GVariant) metadata = NULL; + if (!ostree_repo_read_commit_detached_metadata (repo, + commit_checksum, + &metadata, + cancellable, + error)) + return glnx_prefix_error (error, "Failed to read detached metadata"); + + g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes (commit_variant); + + g_autoptr(GVariant) signatures = NULL; + + const gchar *signature_key = ostree_sign_metadata_key(self); + GVariantType *signature_format = (GVariantType *) ostree_sign_metadata_format(self); + + if (metadata) + signatures = g_variant_lookup_value (metadata, + signature_key, + signature_format); + + + return ostree_sign_data_verify (self, + signed_data, + signatures, + out_success_message, + error); +} + +/** + * ostree_sign_get_name: + * @self: an #OstreeSign object + * + * Return the pointer to the name of currently used/selected signing engine. + * + * Returns: (transfer none): pointer to the name + * @NULL in case of error (unlikely). + * + * Since: 2020.2 + */ +const gchar * +ostree_sign_get_name (OstreeSign *self) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), NULL); + g_return_val_if_fail (OSTREE_SIGN_GET_IFACE (self)->get_name != NULL, NULL); + + return OSTREE_SIGN_GET_IFACE (self)->get_name (self); +} + +/** + * ostree_sign_commit: + * @self: an #OstreeSign object + * @repo: an #OsreeRepo object + * @commit_checksum: SHA256 of given commit to sign + * @cancellable: A #GCancellable + * @error: a #GError + * + * Add a signature to a commit. + * + * Depending of the signing engine used you will need to load + * the secret key with #ostree_sign_set_sk. + * + * Returns: @TRUE if commit has been signed successfully, + * @FALSE in case of error (@error will contain the reason). + * + * Since: 2020.2 + */ +gboolean +ostree_sign_commit (OstreeSign *self, + OstreeRepo *repo, + const gchar *commit_checksum, + GCancellable *cancellable, + GError **error) +{ + + g_autoptr(GBytes) commit_data = NULL; + g_autoptr(GBytes) signature = NULL; + g_autoptr(GVariant) commit_variant = NULL; + g_autoptr(GVariant) old_metadata = NULL; + g_autoptr(GVariant) new_metadata = NULL; + + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, + commit_checksum, &commit_variant, error)) + return glnx_prefix_error (error, "Failed to read commit"); + + if (!ostree_repo_read_commit_detached_metadata (repo, + commit_checksum, + &old_metadata, + cancellable, + error)) + return glnx_prefix_error (error, "Failed to read detached metadata"); + + commit_data = g_variant_get_data_as_bytes (commit_variant); + + if (!ostree_sign_data (self, commit_data, &signature, + cancellable, error)) + return glnx_prefix_error (error, "Not able to sign the cobject"); + + new_metadata = + _sign_detached_metadata_append (self, old_metadata, signature); + + if (!ostree_repo_write_commit_detached_metadata (repo, + commit_checksum, + new_metadata, + cancellable, + error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_sign_get_all: + * + * Return an array with newly allocated instances of all available + * signing engines; they will not be initialized. + * + * Returns: (transfer full) (element-type OstreeSign): an array of signing engines + * + * Since: 2020.2 + */ +GPtrArray * +ostree_sign_get_all (void) +{ + g_autoptr(GPtrArray) engines = g_ptr_array_new_with_free_func (g_object_unref); + for (guint i = 0; i < G_N_ELEMENTS(sign_types); i++) + { + OstreeSign *engine = ostree_sign_get_by_name (sign_types[i].name, NULL); + g_assert (engine); + g_ptr_array_add (engines, engine); + } + + return g_steal_pointer (&engines); +} + +/** + * ostree_sign_get_by_name: + * @name: the name of desired signature engine + * @error: return location for a #GError + * + * Create a new instance of a signing engine. + * + * Returns: (transfer full): New signing engine, or %NULL if the engine is not known + * + * Since: 2020.2 + */ +OstreeSign * +ostree_sign_get_by_name (const gchar *name, GError **error) +{ + + OstreeSign *sign = NULL; + + /* Get types if not initialized yet */ +#if defined(HAVE_LIBSODIUM) + if (sign_types[SIGN_ED25519].type == 0) + sign_types[SIGN_ED25519].type = OSTREE_TYPE_SIGN_ED25519; +#endif + if (sign_types[SIGN_DUMMY].type == 0) + sign_types[SIGN_DUMMY].type = OSTREE_TYPE_SIGN_DUMMY; + + for (gint i=0; i < G_N_ELEMENTS(sign_types); i++) + { + if (g_strcmp0 (name, sign_types[i].name) == 0) + { + g_debug ("Using '%s' signing engine", sign_types[i].name); + sign = g_object_new (sign_types[i].type, NULL); + break; + } + } + + if (sign == NULL) + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Requested signature type is not implemented"); + + return sign; +} + +/** + * ostree_sign_summary: + * @self: Self + * @repo: ostree repository + * @keys: keys -- GVariant containing keys as GVarints specific to signature type. + * @cancellable: A #GCancellable + * @error: a #GError + * + * Add a signature to a summary file. + * Based on ostree_repo_add_gpg_signature_summary implementation. + * + * Returns: @TRUE if summary file has been signed with all provided keys + */ +gboolean +ostree_sign_summary (OstreeSign *self, + OstreeRepo *repo, + GVariant *keys, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + g_return_val_if_fail (OSTREE_IS_REPO (repo), FALSE); + + g_autoptr(GVariant) normalized = NULL; + g_autoptr(GBytes) summary_data = NULL; + g_autoptr(GVariant) metadata = NULL; + + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (repo->repo_dir_fd, "summary", TRUE, &fd, error)) + return FALSE; + summary_data = ot_fd_readall_or_mmap (fd, 0, error); + if (!summary_data) + return FALSE; + + /* Note that fd is reused below */ + glnx_close_fd (&fd); + + if (!ot_openat_ignore_enoent (repo->repo_dir_fd, "summary.sig", &fd, error)) + return FALSE; + + if (fd >= 0) + { + if (!ot_variant_read_fd (fd, 0, OSTREE_SUMMARY_SIG_GVARIANT_FORMAT, + FALSE, &metadata, error)) + return FALSE; + } + + if (g_variant_n_children(keys) == 0) + return glnx_throw (error, "No keys passed for signing summary"); + + GVariantIter *iter; + GVariant *key; + + g_variant_get (keys, "av", &iter); + while (g_variant_iter_loop (iter, "v", &key)) + { + g_autoptr (GBytes) signature = NULL; + + if (!ostree_sign_set_sk (self, key, error)) + return FALSE; + + if (!ostree_sign_data (self, + summary_data, + &signature, + cancellable, + error)) + return FALSE; + + g_autoptr(GVariant) old_metadata = g_steal_pointer (&metadata); + metadata = + _sign_detached_metadata_append (self, old_metadata, signature); + } + g_variant_iter_free (iter); + + normalized = g_variant_get_normal_form (metadata); + if (!_ostree_repo_file_replace_contents (repo, + repo->repo_dir_fd, + "summary.sig", + g_variant_get_data (normalized), + g_variant_get_size (normalized), + cancellable, error)) + return FALSE; + + return TRUE; +} diff --git a/src/libostree/ostree-sign.h b/src/libostree/ostree-sign.h new file mode 100644 index 00000000..0d069059 --- /dev/null +++ b/src/libostree/ostree-sign.h @@ -0,0 +1,171 @@ +/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */ + +/* + * Copyright © 2019 Collabora Ltd. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Denis Pynkin (d4s) + */ + +#pragma once + +#include +#include + +#include "ostree-ref.h" +#include "ostree-remote.h" +#include "ostree-types.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_SIGN (ostree_sign_get_type ()) + +_OSTREE_PUBLIC +GType ostree_sign_get_type (void); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +typedef struct _OstreeSign OstreeSign; +typedef struct _OstreeSignInterface OstreeSignInterface; + +static inline OstreeSign *OSTREE_SIGN (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, ostree_sign_get_type (), OstreeSign); } +static inline gboolean OSTREE_IS_SIGN (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, ostree_sign_get_type ()); } +static inline OstreeSignInterface *OSTREE_SIGN_GET_IFACE (gpointer ptr) { return G_TYPE_INSTANCE_GET_INTERFACE (ptr, ostree_sign_get_type (), OstreeSignInterface); } +G_GNUC_END_IGNORE_DEPRECATIONS + +/** + * OSTREE_SIGN_NAME_ED25519: + * The name of the default ed25519 signing type. + */ +#define OSTREE_SIGN_NAME_ED25519 "ed25519" + +/* Have to use glib-2.44 for this +_OSTREE_PUBLIC +G_DECLARE_INTERFACE (OstreeSign, ostree_sign, OSTREE, SIGN, GObject) +*/ + +struct _OstreeSignInterface +{ + GTypeInterface g_iface; + const gchar *(* get_name) (OstreeSign *self); + gboolean (* data) (OstreeSign *self, + GBytes *data, + GBytes **signature, + GCancellable *cancellable, + GError **error); + gboolean (* data_verify) (OstreeSign *self, + GBytes *data, + GVariant *signatures, + char **out_success_message, + GError **error); + const gchar *(* metadata_key) (OstreeSign *self); + const gchar *(* metadata_format) (OstreeSign *self); + gboolean (* clear_keys) (OstreeSign *self, + GError **error); + gboolean (* set_sk) (OstreeSign *self, + GVariant *secret_key, + GError **error); + gboolean (* set_pk) (OstreeSign *self, + GVariant *public_key, + GError **error); + gboolean (* add_pk) (OstreeSign *self, + GVariant *public_key, + GError **error); + gboolean (* load_pk) (OstreeSign *self, + GVariant *options, + GError **error); +}; + +_OSTREE_PUBLIC +const gchar * ostree_sign_get_name (OstreeSign *self); + +_OSTREE_PUBLIC +gboolean ostree_sign_data (OstreeSign *self, + GBytes *data, + GBytes **signature, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_data_verify (OstreeSign *self, + GBytes *data, + GVariant *signatures, + char **out_success_message, + GError **error); + +_OSTREE_PUBLIC +const gchar * ostree_sign_metadata_key (OstreeSign *self); + +_OSTREE_PUBLIC +const gchar * ostree_sign_metadata_format (OstreeSign *self); + +_OSTREE_PUBLIC +gboolean ostree_sign_commit (OstreeSign *self, + OstreeRepo *repo, + const gchar *commit_checksum, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_commit_verify (OstreeSign *self, + OstreeRepo *repo, + const gchar *commit_checksum, + char **out_success_message, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_clear_keys (OstreeSign *self, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_set_sk (OstreeSign *self, + GVariant *secret_key, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_set_pk (OstreeSign *self, + GVariant *public_key, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_add_pk (OstreeSign *self, + GVariant *public_key, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_load_pk (OstreeSign *self, + GVariant *options, + GError **error); + + +_OSTREE_PUBLIC +GPtrArray * ostree_sign_get_all(void); + +_OSTREE_PUBLIC +OstreeSign * ostree_sign_get_by_name (const gchar *name, GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_summary (OstreeSign *self, + OstreeRepo *repo, + GVariant *keys, + GCancellable *cancellable, + GError **error); +G_END_DECLS + diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index ee00c02c..cb593020 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -217,6 +217,79 @@ dirfd_copy_attributes_and_xattrs (int src_parent_dfd, return TRUE; } +static gint +str_sort_cb (gconstpointer name_ptr_a, gconstpointer name_ptr_b) +{ + const gchar *name_a = *((const gchar **) name_ptr_a); + const gchar *name_b = *((const gchar **) name_ptr_b); + + return g_strcmp0 (name_a, name_b); +} + +static gboolean +checksum_dir_recurse (int dfd, + const char *path, + OtChecksum *checksum, + GCancellable *cancellable, + GError **error) +{ + g_auto(GLnxDirFdIterator) dfditer = { 0, }; + g_autoptr (GPtrArray) d_entries = g_ptr_array_new_with_free_func (g_free); + + if (!glnx_dirfd_iterator_init_at (dfd, path, TRUE, &dfditer, error)) + return FALSE; + + while (TRUE) + { + struct dirent *dent; + + if (!glnx_dirfd_iterator_next_dent (&dfditer, &dent, cancellable, error)) + return FALSE; + + if (dent == NULL) + break; + + g_ptr_array_add (d_entries, g_strdup (dent->d_name)); + } + + /* File systems do not guarantee dir entry order, make sure this is + * reproducable + */ + g_ptr_array_sort(d_entries, str_sort_cb); + + for (gint i=0; i < d_entries->len; i++) + { + const gchar *d_name = (gchar *)g_ptr_array_index (d_entries, i); + struct stat stbuf; + + if (!glnx_fstatat (dfditer.fd, d_name, &stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + + if (S_ISDIR (stbuf.st_mode)) + { + if (!checksum_dir_recurse(dfditer.fd, d_name, checksum, cancellable, error)) + return FALSE; + } + else + { + int fd; + + if (!ot_openat_ignore_enoent (dfditer.fd, d_name, &fd, error)) + return FALSE; + if (fd != -1) + { + g_autoptr(GInputStream) in = g_unix_input_stream_new (fd, FALSE); + if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) + return FALSE; + } + } + + } + + return TRUE; +} + static gboolean copy_dir_recurse (int src_parent_dfd, int dest_parent_dfd, @@ -1065,6 +1138,9 @@ get_kernel_from_tree_usrlib_modules (int deployment_dfd, g_clear_object (&in); glnx_close_fd (&fd); + /* Check for /usr/lib/modules/$kver/devicetree first, if it does not + * exist check for /usr/lib/modules/$kver/dtb/ directory. + */ if (!ot_openat_ignore_enoent (ret_layout->boot_dfd, "devicetree", &fd, error)) return FALSE; if (fd != -1) @@ -1075,6 +1151,23 @@ get_kernel_from_tree_usrlib_modules (int deployment_dfd, if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error)) return FALSE; } + else + { + struct stat stbuf; + /* Check for dtb directory */ + if (!glnx_fstatat_allow_noent (ret_layout->boot_dfd, "dtb", &stbuf, 0, error)) + return FALSE; + + if (errno == 0 && S_ISDIR (stbuf.st_mode)) + { + /* devicetree_namever set to NULL indicates a complete directory */ + ret_layout->devicetree_srcpath = g_strdup ("dtb"); + ret_layout->devicetree_namever = NULL; + + if (!checksum_dir_recurse(ret_layout->boot_dfd, "dtb", &checksum, cancellable, error)) + return FALSE; + } + } g_clear_object (&in); glnx_close_fd (&fd); @@ -1730,15 +1823,24 @@ install_deployment_kernel (OstreeSysroot *sysroot, if (kernel_layout->devicetree_srcpath) { - g_assert (kernel_layout->devicetree_namever); - if (!glnx_fstatat_allow_noent (bootcsum_dfd, kernel_layout->devicetree_namever, &stbuf, 0, error)) - return FALSE; - if (errno == ENOENT) + /* If devicetree_namever is set a single device tree is deployed */ + if (kernel_layout->devicetree_namever) { - if (!install_into_boot (repo, sepolicy, kernel_layout->boot_dfd, kernel_layout->devicetree_srcpath, - bootcsum_dfd, kernel_layout->devicetree_namever, - sysroot->debug_flags, - cancellable, error)) + if (!glnx_fstatat_allow_noent (bootcsum_dfd, kernel_layout->devicetree_namever, &stbuf, 0, error)) + return FALSE; + if (errno == ENOENT) + { + if (!install_into_boot (repo, sepolicy, kernel_layout->boot_dfd, kernel_layout->devicetree_srcpath, + bootcsum_dfd, kernel_layout->devicetree_namever, + sysroot->debug_flags, + cancellable, error)) + return FALSE; + } + } + else + { + if (!copy_dir_recurse(kernel_layout->boot_dfd, bootcsum_dfd, kernel_layout->devicetree_srcpath, + sysroot->debug_flags, cancellable, error)) return FALSE; } } @@ -1850,6 +1952,15 @@ install_deployment_kernel (OstreeSysroot *sysroot, g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->devicetree_namever, NULL); ostree_bootconfig_parser_set (bootconfig, "devicetree", boot_relpath); } + else if (kernel_layout->devicetree_srcpath) + { + /* If devicetree_srcpath is set but devicetree_namever is NULL, then we + * want to point to a whole directory of device trees. + * See: https://github.com/ostreedev/ostree/issues/1900 + */ + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->devicetree_srcpath, NULL); + ostree_bootconfig_parser_set (bootconfig, "fdtdir", boot_relpath); + } /* Note this is parsed in ostree-impl-system-generator.c */ g_autofree char *ostree_kernel_arg = g_strdup_printf ("ostree=/ostree/boot.%d/%s/%s/%d", diff --git a/src/libostree/ostree-sysroot-upgrader.c b/src/libostree/ostree-sysroot-upgrader.c index 8fb231a3..46813358 100644 --- a/src/libostree/ostree-sysroot-upgrader.c +++ b/src/libostree/ostree-sysroot-upgrader.c @@ -530,8 +530,8 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self, g_variant_new_variant (g_variant_new_int32 (flags))); /* Add the timestamp check, unless disabled */ if ((upgrader_flags & OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER) == 0) - g_variant_builder_add (optbuilder, "{s@v}", "timestamp-check", - g_variant_new_variant (g_variant_new_boolean (TRUE))); + g_variant_builder_add (optbuilder, "{s@v}", "timestamp-check-from-rev", + g_variant_new_variant (g_variant_new_string (from_revision))); g_variant_builder_add (optbuilder, "{s@v}", "refs", g_variant_new_variant (g_variant_new_strv ((const char *const*) refs_to_fetch, -1))); diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index 55a61014..0dc7a392 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -988,30 +988,12 @@ _ostree_sysroot_reload_staged (OstreeSysroot *self, return TRUE; } -/** - * ostree_sysroot_load_if_changed: - * @self: #OstreeSysroot - * @out_changed: (out caller-allocates): - * @cancellable: Cancellable - * @error: Error - * - * Since: 2016.4 - */ -gboolean -ostree_sysroot_load_if_changed (OstreeSysroot *self, - gboolean *out_changed, - GCancellable *cancellable, - GError **error) +static gboolean +sysroot_load_from_bootloader_configs (OstreeSysroot *self, + GCancellable *cancellable, + GError **error) { - if (!ostree_sysroot_initialize (self, error)) - return FALSE; - - /* Here we also lazily initialize the repository. We didn't do this - * previous to v2017.6, but we do now to support the error-free - * ostree_sysroot_repo() API. - */ - if (!ensure_repo (self, error)) - return FALSE; + struct stat stbuf; int bootversion = 0; if (!read_current_bootversion (self, &bootversion, cancellable, error)) @@ -1022,27 +1004,6 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self, cancellable, error)) return FALSE; - struct stat stbuf; - if (!glnx_fstatat (self->sysroot_fd, "ostree/deploy", &stbuf, 0, error)) - return FALSE; - - if (out_changed) - { - if (self->loaded_ts.tv_sec == stbuf.st_mtim.tv_sec && - self->loaded_ts.tv_nsec == stbuf.st_mtim.tv_nsec) - { - *out_changed = FALSE; - /* Note early return */ - return TRUE; - } - } - - g_clear_pointer (&self->deployments, g_ptr_array_unref); - g_clear_object (&self->booted_deployment); - g_clear_object (&self->staged_deployment); - self->bootversion = -1; - self->subbootversion = -1; - g_autoptr(GPtrArray) boot_loader_configs = NULL; if (!_ostree_sysroot_read_boot_loader_configs (self, bootversion, &boot_loader_configs, cancellable, error)) @@ -1120,8 +1081,60 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self, self->bootversion = bootversion; self->subbootversion = subbootversion; - self->deployments = deployments; - deployments = NULL; /* Transfer ownership */ + self->deployments = g_steal_pointer (&deployments); + + return TRUE; +} + +/** + * ostree_sysroot_load_if_changed: + * @self: #OstreeSysroot + * @out_changed: (out caller-allocates): + * @cancellable: Cancellable + * @error: Error + * + * Since: 2016.4 + */ +gboolean +ostree_sysroot_load_if_changed (OstreeSysroot *self, + gboolean *out_changed, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("loading sysroot", error); + + if (!ostree_sysroot_initialize (self, error)) + return FALSE; + + /* Here we also lazily initialize the repository. We didn't do this + * previous to v2017.6, but we do now to support the error-free + * ostree_sysroot_repo() API. + */ + if (!ensure_repo (self, error)) + return FALSE; + + struct stat stbuf; + if (!glnx_fstatat (self->sysroot_fd, "ostree/deploy", &stbuf, 0, error)) + return FALSE; + + if (self->loaded_ts.tv_sec == stbuf.st_mtim.tv_sec && + self->loaded_ts.tv_nsec == stbuf.st_mtim.tv_nsec) + { + if (out_changed) + *out_changed = FALSE; + /* Note early return */ + return TRUE; + } + + g_clear_pointer (&self->deployments, g_ptr_array_unref); + g_clear_object (&self->booted_deployment); + g_clear_object (&self->staged_deployment); + self->bootversion = -1; + self->subbootversion = -1; + + if (!sysroot_load_from_bootloader_configs (self, cancellable, error)) + return FALSE; + self->loaded_ts = stbuf.st_mtim; if (out_changed) diff --git a/src/libostree/ostree-sysroot.h b/src/libostree/ostree-sysroot.h index af8192fc..d9f5a546 100644 --- a/src/libostree/ostree-sysroot.h +++ b/src/libostree/ostree-sysroot.h @@ -101,9 +101,6 @@ GFile * ostree_sysroot_get_deployment_origin_path (GFile *deployment_path); _OSTREE_PUBLIC gboolean ostree_sysroot_lock (OstreeSysroot *self, GError **error); -_OSTREE_PUBLIC -gboolean ostree_sysroot_lock_with_mount_namespace (OstreeSysroot *self, GError **error); - _OSTREE_PUBLIC gboolean ostree_sysroot_try_lock (OstreeSysroot *self, gboolean *out_acquired, diff --git a/src/libostree/ostree-version.h b/src/libostree/ostree-version.h index 4ed20af1..f9c398e9 100644 --- a/src/libostree/ostree-version.h +++ b/src/libostree/ostree-version.h @@ -43,7 +43,7 @@ * * Since: 2017.4 */ -#define OSTREE_RELEASE_VERSION (3) +#define OSTREE_RELEASE_VERSION (4) /** * OSTREE_VERSION @@ -52,7 +52,7 @@ * * Since: 2017.4 */ -#define OSTREE_VERSION (2020.3) +#define OSTREE_VERSION (2020.4) /** * OSTREE_VERSION_S: @@ -62,7 +62,7 @@ * * Since: 2017.4 */ -#define OSTREE_VERSION_S "2020.3" +#define OSTREE_VERSION_S "2020.4" #define OSTREE_ENCODE_VERSION(year,release) \ ((year) << 16 | (release)) diff --git a/src/libostree/ostree.h b/src/libostree/ostree.h index 49ca919c..0308d0ed 100644 --- a/src/libostree/ostree.h +++ b/src/libostree/ostree.h @@ -40,5 +40,6 @@ #include #include #include +#include #include #include diff --git a/src/ostree/main.c b/src/ostree/main.c index a523ff9a..a9f57392 100644 --- a/src/ostree/main.c +++ b/src/ostree/main.c @@ -109,6 +109,9 @@ static OstreeCommand commands[] = { { "rev-parse", OSTREE_BUILTIN_FLAG_NONE, ostree_builtin_rev_parse, "Output the target of a rev" }, + { "sign", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_sign, + "Sign a commit" }, { "show", OSTREE_BUILTIN_FLAG_NONE, ostree_builtin_show, "Output a metadata object" }, diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c index c1c3353d..bcece3f6 100644 --- a/src/ostree/ot-admin-builtin-deploy.c +++ b/src/ostree/ot-admin-builtin-deploy.c @@ -37,6 +37,7 @@ static gboolean opt_retain_pending; static gboolean opt_retain_rollback; static gboolean opt_not_as_default; static gboolean opt_no_prune; +static gboolean opt_no_merge; static char **opt_kernel_argv; static char **opt_kernel_argv_append; static gboolean opt_kernel_proc_cmdline; @@ -48,6 +49,7 @@ static GOptionEntry options[] = { { "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" }, { "origin-file", 0, 0, G_OPTION_ARG_FILENAME, &opt_origin_path, "Specify origin file", "FILENAME" }, { "no-prune", 0, 0, G_OPTION_ARG_NONE, &opt_no_prune, "Don't prune the repo when done", NULL}, + { "no-merge", 0, 0, G_OPTION_ARG_NONE, &opt_no_merge, "Do not apply configuration (/etc and kernel arguments) from booted deployment", NULL}, { "retain", 0, 0, G_OPTION_ARG_NONE, &opt_retain, "Do not delete previous deployments", NULL }, { "stage", 0, 0, G_OPTION_ARG_NONE, &opt_stage, "Complete deployment at OS shutdown", NULL }, { "retain-pending", 0, 0, G_OPTION_ARG_NONE, &opt_retain_pending, "Do not delete pending deployments", NULL }, @@ -113,7 +115,7 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeCommandInvocation *invocat return FALSE; g_autoptr(OstreeDeployment) merge_deployment = - ostree_sysroot_get_merge_deployment (sysroot, opt_osname); + opt_no_merge ? NULL : ostree_sysroot_get_merge_deployment (sysroot, opt_osname); /* Here we perform cleanup of any leftover data from previous * partial failures. This avoids having to call diff --git a/src/ostree/ot-admin-builtin-pin.c b/src/ostree/ot-admin-builtin-pin.c index ced0fcf3..d4337e33 100644 --- a/src/ostree/ot-admin-builtin-pin.c +++ b/src/ostree/ot-admin-builtin-pin.c @@ -52,39 +52,28 @@ ot_admin_builtin_pin (int argc, char **argv, OstreeCommandInvocation *invocation return FALSE; } - unsigned int nsuccess = 0; for (unsigned int i = 1; i < argc; i++) { const char *deploy_index_str = argv[i]; const int deploy_index = atoi (deploy_index_str); - g_autoptr(GError) e = NULL; - g_autoptr(OstreeDeployment) target_deployment = ot_admin_get_indexed_deployment (sysroot, deploy_index, &e); + g_autoptr(OstreeDeployment) target_deployment = ot_admin_get_indexed_deployment (sysroot, deploy_index, error); if (!target_deployment) - { - g_print ("Invalid deployment %s: %s\n", deploy_index_str, e->message); - continue; - } + return FALSE; gboolean current_pin = ostree_deployment_is_pinned (target_deployment); const gboolean desired_pin = !opt_unpin; if (current_pin == desired_pin) { g_print ("Deployment %s is already %s\n", deploy_index_str, current_pin ? "pinned" : "unpinned"); - nsuccess++; } else { - g_autoptr(GError) e = NULL; - if (ostree_sysroot_deployment_set_pinned (sysroot, target_deployment, desired_pin, &e)) - { - g_print ("Deployment %s is now %s\n", deploy_index_str, desired_pin ? "pinned" : "unpinned"); - nsuccess++; - } - else - g_print ("Failed to %s deployment %s: %s\n", desired_pin ? "pin" : "unpin", deploy_index_str, e->message); + if (!ostree_sysroot_deployment_set_pinned (sysroot, target_deployment, desired_pin, error)) + return FALSE; + g_print ("Deployment %s is now %s\n", deploy_index_str, desired_pin ? "pinned" : "unpinned"); } } - return nsuccess > 0; + return TRUE; } diff --git a/src/ostree/ot-builtin-checkout.c b/src/ostree/ot-builtin-checkout.c index a0fe4be4..813dbb9e 100644 --- a/src/ostree/ot-builtin-checkout.c +++ b/src/ostree/ot-builtin-checkout.c @@ -87,7 +87,7 @@ static GOptionEntry options[] = { { "force-copy-zerosized", 'z', 0, G_OPTION_ARG_NONE, &opt_force_copy_zerosized, "Do not hardlink zero-sized files", NULL }, { "force-copy", 'C', 0, G_OPTION_ARG_NONE, &opt_force_copy, "Never hardlink (but may reflink if available)", NULL }, { "bareuseronly-dirs", 'M', 0, G_OPTION_ARG_NONE, &opt_bareuseronly_dirs, "Suppress mode bits outside of 0775 for directories (suid, world writable, etc.)", NULL }, - { "skip-list", 0, 0, G_OPTION_ARG_FILENAME, &opt_skiplist_file, "File containing list of files to skip", "PATH" }, + { "skip-list", 0, 0, G_OPTION_ARG_FILENAME, &opt_skiplist_file, "File containing list of files to skip", "FILE" }, { "selinux-policy", 0, 0, G_OPTION_ARG_FILENAME, &opt_selinux_policy, "Set SELinux labels based on policy in root filesystem PATH (may be /); implies --force-copy", "PATH" }, { "selinux-prefix", 0, 0, G_OPTION_ARG_STRING, &opt_selinux_prefix, "When setting SELinux labels, prefix all paths by PREFIX", "PREFIX" }, { NULL } diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c index 0eea09d7..20409fc2 100644 --- a/src/ostree/ot-builtin-commit.c +++ b/src/ostree/ot-builtin-commit.c @@ -31,6 +31,7 @@ #include "parse-datetime.h" #include "ostree-repo-private.h" #include "ostree-libarchive-private.h" +#include "ostree-sign.h" static char *opt_subject; static char *opt_body; @@ -53,17 +54,22 @@ static gboolean opt_tar_autocreate_parents; static char *opt_tar_pathname_filter; static gboolean opt_no_xattrs; static char *opt_selinux_policy; +static gboolean opt_selinux_policy_from_base; static gboolean opt_canonical_permissions; +static gboolean opt_ro_executables; static gboolean opt_consume; static gboolean opt_devino_canonical; +static char *opt_base; static char **opt_trees; static gint opt_owner_uid = -1; static gint opt_owner_gid = -1; static gboolean opt_table_output; #ifndef OSTREE_DISABLE_GPGME -static char **opt_key_ids; +static char **opt_gpg_key_ids; static char *opt_gpg_homedir; #endif +static char **opt_key_ids; +static char *opt_sign_name; static gboolean opt_generate_sizes; static gboolean opt_disable_fsync; static char *opt_timestamp; @@ -97,6 +103,7 @@ static GOptionEntry options[] = { { "orphan", 0, 0, G_OPTION_ARG_NONE, &opt_orphan, "Create a commit without writing a ref", NULL }, { "no-bindings", 0, 0, G_OPTION_ARG_NONE, &opt_no_bindings, "Do not write any ref bindings", NULL }, { "bind-ref", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_bind_refs, "Add a ref to ref binding commit metadata", "BRANCH" }, + { "base", 0, 0, G_OPTION_ARG_STRING, &opt_base, "Start from the given commit as a base (no modifiers apply)", "REF" }, { "tree", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_trees, "Overlay the given argument as a tree", "dir=PATH or tar=TARFILE or ref=COMMIT" }, { "add-metadata-string", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_strings, "Add a key/value pair to metadata", "KEY=VALUE" }, { "add-metadata", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_variants, "Add a key/value pair to metadata, where the KEY is a string, an VALUE is g_variant_parse() formatted", "KEY=VALUE" }, @@ -105,8 +112,10 @@ static GOptionEntry options[] = { { "owner-uid", 0, 0, G_OPTION_ARG_INT, &opt_owner_uid, "Set file ownership user id", "UID" }, { "owner-gid", 0, 0, G_OPTION_ARG_INT, &opt_owner_gid, "Set file ownership group id", "GID" }, { "canonical-permissions", 0, 0, G_OPTION_ARG_NONE, &opt_canonical_permissions, "Canonicalize permissions in the same way bare-user does for hardlinked files", NULL }, + { "mode-ro-executables", 0, 0, G_OPTION_ARG_NONE, &opt_ro_executables, "Ensure executable files are not writable", NULL }, { "no-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_no_xattrs, "Do not import extended attributes", NULL }, { "selinux-policy", 0, 0, G_OPTION_ARG_FILENAME, &opt_selinux_policy, "Set SELinux labels based on policy in root filesystem PATH (may be /)", "PATH" }, + { "selinux-policy-from-base", 'P', 0, G_OPTION_ARG_NONE, &opt_selinux_policy_from_base, "Set SELinux labels based on first --tree argument", NULL }, { "link-checkout-speedup", 0, 0, G_OPTION_ARG_NONE, &opt_link_checkout_speedup, "Optimize for commits of trees composed of hardlinks into the repository", NULL }, { "devino-canonical", 'I', 0, G_OPTION_ARG_NONE, &opt_devino_canonical, "Assume hardlinked objects are unmodified. Implies --link-checkout-speedup", NULL }, { "tar-autocreate-parents", 0, 0, G_OPTION_ARG_NONE, &opt_tar_autocreate_parents, "When loading tar archives, automatically create parent directories as needed", NULL }, @@ -117,9 +126,11 @@ static GOptionEntry options[] = { { "consume", 0, 0, G_OPTION_ARG_NONE, &opt_consume, "Consume (delete) content after commit (for local directories)", NULL }, { "table-output", 0, 0, G_OPTION_ARG_NONE, &opt_table_output, "Output more information in a KEY: VALUE format", NULL }, #ifndef OSTREE_DISABLE_GPGME - { "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the commit with", "KEY-ID"}, + { "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_gpg_key_ids, "GPG Key ID to sign the commit with", "KEY-ID"}, { "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"}, #endif + { "sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "Sign the commit with", "KEY_ID"}, + { "sign-type", 0, 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME"}, { "generate-sizes", 0, 0, G_OPTION_ARG_NONE, &opt_generate_sizes, "Generate size information along with commit metadata", NULL }, { "disable-fsync", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, { "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", "POLICY" }, @@ -185,13 +196,19 @@ commit_filter (OstreeRepo *self, g_file_info_set_attribute_uint32 (file_info, "unix::uid", opt_owner_uid); if (opt_owner_gid >= 0) g_file_info_set_attribute_uint32 (file_info, "unix::gid", opt_owner_gid); + guint mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); + + if (S_ISREG (mode) && opt_ro_executables && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + { + mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); + g_file_info_set_attribute_uint32 (file_info, "unix::mode", mode); + } if (mode_adds && g_hash_table_lookup_extended (mode_adds, path, NULL, &value)) { - guint current_mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); guint mode_add = GPOINTER_TO_UINT (value); g_file_info_set_attribute_uint32 (file_info, "unix::mode", - current_mode | mode_add); + mode | mode_add); g_hash_table_remove (mode_adds, path); } else if (mode_overrides && g_hash_table_lookup_extended (mode_overrides, path, NULL, &value)) @@ -417,6 +434,7 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio OstreeRepoTransactionStats stats; struct CommitFilterData filter_data = { 0, }; g_autofree char *commit_body = NULL; + g_autoptr (OstreeSign) sign = NULL; context = g_option_context_new ("[PATH]"); @@ -550,6 +568,11 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio flags |= OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES; if (opt_disable_fsync) ostree_repo_set_disable_fsync (repo, TRUE); + if (opt_selinux_policy && opt_selinux_policy_from_base) + { + glnx_throw (error, "Cannot specify both --selinux-policy and --selinux-policy-from-base"); + goto out; + } if (flags != 0 || opt_owner_uid >= 0 @@ -557,25 +580,14 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio || opt_statoverride_file != NULL || opt_skiplist_file != NULL || opt_no_xattrs - || opt_selinux_policy) + || opt_ro_executables + || opt_selinux_policy + || opt_selinux_policy_from_base) { filter_data.mode_adds = mode_adds; filter_data.skip_list = skip_list; modifier = ostree_repo_commit_modifier_new (flags, commit_filter, &filter_data, NULL); - if (opt_selinux_policy) - { - glnx_autofd int rootfs_dfd = -1; - if (!glnx_opendirat (AT_FDCWD, opt_selinux_policy, TRUE, &rootfs_dfd, error)) - { - g_prefix_error (error, "selinux-policy: "); - goto out; - } - policy = ostree_sepolicy_new_at (rootfs_dfd, cancellable, error); - if (!policy) - goto out; - ostree_repo_commit_modifier_set_sepolicy (modifier, policy); - } } if (opt_editor) @@ -599,129 +611,180 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio if (opt_link_checkout_speedup && !ostree_repo_scan_hardlinks (repo, cancellable, error)) goto out; - mtree = ostree_mutable_tree_new (); - - if (argc <= 1 && (opt_trees == NULL || opt_trees[0] == NULL)) + if (opt_base) { - if (!ostree_repo_write_dfd_to_mtree (repo, AT_FDCWD, ".", mtree, modifier, - cancellable, error)) + g_autofree char *base_commit = NULL; + g_autoptr(GFile) root = NULL; + if (!ostree_repo_read_commit (repo, opt_base, &root, &base_commit, cancellable, error)) goto out; - } - else if (opt_trees != NULL) - { - const char *const*tree_iter; - const char *tree; - const char *eq; + OstreeRepoFile *rootf = (OstreeRepoFile*) root; - for (tree_iter = (const char *const*)opt_trees; *tree_iter; tree_iter++) + mtree = ostree_mutable_tree_new_from_checksum (repo, + ostree_repo_file_tree_get_contents_checksum (rootf), + ostree_repo_file_tree_get_metadata_checksum (rootf)); + + if (opt_selinux_policy_from_base) { - tree = *tree_iter; - - eq = strchr (tree, '='); - if (!eq) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Missing type in tree specification '%s'", tree); - goto out; - } - g_free (tree_type); - tree_type = g_strndup (tree, eq - tree); - tree = eq + 1; - - g_clear_object (&object_to_commit); - if (strcmp (tree_type, "dir") == 0) - { - if (!ostree_repo_write_dfd_to_mtree (repo, AT_FDCWD, tree, mtree, modifier, - cancellable, error)) - goto out; - } - else if (strcmp (tree_type, "tar") == 0) - { - if (!opt_tar_pathname_filter) - { - if (strcmp (tree, "-") == 0) - { - if (!ostree_repo_write_archive_to_mtree_from_fd (repo, STDIN_FILENO, mtree, modifier, - opt_tar_autocreate_parents, - cancellable, error)) - goto out; - } - else - { - object_to_commit = g_file_new_for_path (tree); - - if (!ostree_repo_write_archive_to_mtree (repo, object_to_commit, mtree, modifier, - opt_tar_autocreate_parents, - cancellable, error)) - goto out; - } - } - else - { -#ifdef HAVE_LIBARCHIVE - const char *comma = strchr (opt_tar_pathname_filter, ','); - if (!comma) - { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Missing ',' in --tar-pathname-filter"); - goto out; - } - const char *replacement = comma + 1; - g_autofree char *regexp_text = g_strndup (opt_tar_pathname_filter, comma - opt_tar_pathname_filter); - /* Use new API if we have a pathname filter */ - OstreeRepoImportArchiveOptions opts = { 0, }; - opts.autocreate_parents = opt_tar_autocreate_parents; - opts.translate_pathname = handle_translate_pathname; - g_autoptr(GRegex) regexp = g_regex_new (regexp_text, 0, 0, error); - TranslatePathnameData tpdata = { regexp, replacement }; - if (!regexp) - { - g_prefix_error (error, "--tar-pathname-filter: "); - goto out; - } - opts.translate_pathname_user_data = &tpdata; - - g_autoptr(OtAutoArchiveRead) archive; - if (strcmp (tree, "-") == 0) - archive = ot_open_archive_read_fd (STDIN_FILENO, error); - else - archive = ot_open_archive_read (tree, error); - - if (!archive) - goto out; - if (!ostree_repo_import_archive_to_mtree (repo, &opts, archive, mtree, - modifier, cancellable, error)) - goto out; -#else - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "This version of ostree is not compiled with libarchive support"); - goto out; -#endif - } - } - else if (strcmp (tree_type, "ref") == 0) - { - if (!ostree_repo_read_commit (repo, tree, &object_to_commit, NULL, cancellable, error)) - goto out; - - if (!ostree_repo_write_directory_to_mtree (repo, object_to_commit, mtree, modifier, - cancellable, error)) - goto out; - } - else - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid tree type specification '%s'", tree_type); - goto out; - } + g_assert (modifier); + if (!ostree_repo_commit_modifier_set_sepolicy_from_commit (modifier, repo, base_commit, cancellable, error)) + goto out; + /* Don't try to handle it twice */ + opt_selinux_policy_from_base = FALSE; } } else { - g_assert (argc > 1); - if (!ostree_repo_write_dfd_to_mtree (repo, AT_FDCWD, argv[1], mtree, modifier, - cancellable, error)) - goto out; + mtree = ostree_mutable_tree_new (); + } + + + /* Convert implicit . or explicit path via argv into + * --tree=dir= so that we only have one primary code path below. + */ + if (opt_trees == NULL || opt_trees[0] == NULL) + { + char *path; + if (argc <= 1) + path = "."; + else + path = argv[1]; + opt_trees = g_new0 (char *, 2); + opt_trees[0] = g_strconcat ("dir=", path, NULL); + } + + const char *const*tree_iter; + const char *tree; + const char *eq; + g_assert (opt_trees && *opt_trees); + for (tree_iter = (const char *const*)opt_trees; *tree_iter; tree_iter++) + { + const gboolean first = (tree_iter == (const char *const*)opt_trees); + tree = *tree_iter; + + eq = strchr (tree, '='); + if (!eq) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Missing type in tree specification '%s'", tree); + goto out; + } + g_free (tree_type); + tree_type = g_strndup (tree, eq - tree); + tree = eq + 1; + + g_clear_object (&object_to_commit); + if (strcmp (tree_type, "dir") == 0) + { + if (first && opt_selinux_policy_from_base) + { + opt_selinux_policy = g_strdup (tree); + opt_selinux_policy_from_base = FALSE; + } + if (first && opt_selinux_policy) + { + g_assert (modifier); + glnx_autofd int rootfs_dfd = -1; + if (!glnx_opendirat (AT_FDCWD, opt_selinux_policy, TRUE, &rootfs_dfd, error)) + goto out; + policy = ostree_sepolicy_new_at (rootfs_dfd, cancellable, error); + if (!policy) + goto out; + ostree_repo_commit_modifier_set_sepolicy (modifier, policy); + } + if (!ostree_repo_write_dfd_to_mtree (repo, AT_FDCWD, tree, mtree, modifier, + cancellable, error)) + goto out; + } + else if (strcmp (tree_type, "tar") == 0) + { + if (first && opt_selinux_policy_from_base) + { + glnx_throw (error, "Cannot use --selinux-policy-from-base with tar"); + goto out; + } + if (!opt_tar_pathname_filter) + { + if (strcmp (tree, "-") == 0) + { + if (!ostree_repo_write_archive_to_mtree_from_fd (repo, STDIN_FILENO, mtree, modifier, + opt_tar_autocreate_parents, + cancellable, error)) + goto out; + } + else + { + object_to_commit = g_file_new_for_path (tree); + + if (!ostree_repo_write_archive_to_mtree (repo, object_to_commit, mtree, modifier, + opt_tar_autocreate_parents, + cancellable, error)) + goto out; + } + } + else + { +#ifdef HAVE_LIBARCHIVE + const char *comma = strchr (opt_tar_pathname_filter, ','); + if (!comma) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Missing ',' in --tar-pathname-filter"); + goto out; + } + const char *replacement = comma + 1; + g_autofree char *regexp_text = g_strndup (opt_tar_pathname_filter, comma - opt_tar_pathname_filter); + /* Use new API if we have a pathname filter */ + OstreeRepoImportArchiveOptions opts = { 0, }; + opts.autocreate_parents = opt_tar_autocreate_parents; + opts.translate_pathname = handle_translate_pathname; + g_autoptr(GRegex) regexp = g_regex_new (regexp_text, 0, 0, error); + TranslatePathnameData tpdata = { regexp, replacement }; + if (!regexp) + { + g_prefix_error (error, "--tar-pathname-filter: "); + goto out; + } + opts.translate_pathname_user_data = &tpdata; + + g_autoptr(OtAutoArchiveRead) archive; + if (strcmp (tree, "-") == 0) + archive = ot_open_archive_read_fd (STDIN_FILENO, error); + else + archive = ot_open_archive_read (tree, error); + + if (!archive) + goto out; + if (!ostree_repo_import_archive_to_mtree (repo, &opts, archive, mtree, + modifier, cancellable, error)) + goto out; +#else + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "This version of ostree is not compiled with libarchive support"); + goto out; +#endif + } + } + else if (strcmp (tree_type, "ref") == 0) + { + if (first && opt_selinux_policy_from_base) + { + g_assert (modifier); + if (!ostree_repo_commit_modifier_set_sepolicy_from_commit (modifier, repo, tree, cancellable, error)) + goto out; + } + if (!ostree_repo_read_commit (repo, tree, &object_to_commit, NULL, cancellable, error)) + goto out; + + if (!ostree_repo_write_directory_to_mtree (repo, object_to_commit, mtree, modifier, + cancellable, error)) + goto out; + } + else + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid tree type specification '%s'", tree_type); + goto out; + } } if (mode_adds && g_hash_table_size (mode_adds) > 0) @@ -811,12 +874,41 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio goto out; } -#ifndef OSTREE_DISABLE_GPGME if (opt_key_ids) { + /* Initialize crypto system */ + opt_sign_name = opt_sign_name ?: OSTREE_SIGN_NAME_ED25519; + + sign = ostree_sign_get_by_name (opt_sign_name, error); + if (sign == NULL) + goto out; + char **iter; for (iter = opt_key_ids; iter && *iter; iter++) + { + const char *keyid = *iter; + g_autoptr (GVariant) secret_key = NULL; + + secret_key = g_variant_new_string (keyid); + if (!ostree_sign_set_sk (sign, secret_key, error)) + goto out; + + if (!ostree_sign_commit (sign, + repo, + commit_checksum, + cancellable, + error)) + goto out; + } + } + +#ifndef OSTREE_DISABLE_GPGME + if (opt_gpg_key_ids) + { + char **iter; + + for (iter = opt_gpg_key_ids; iter && *iter; iter++) { const char *keyid = *iter; diff --git a/src/ostree/ot-builtin-diff.c b/src/ostree/ot-builtin-diff.c index 1f0488de..82a533d5 100644 --- a/src/ostree/ot-builtin-diff.c +++ b/src/ostree/ot-builtin-diff.c @@ -142,7 +142,7 @@ ostree_builtin_diff (int argc, char **argv, OstreeCommandInvocation *invocation, g_autoptr(GPtrArray) removed = NULL; g_autoptr(GPtrArray) added = NULL; - context = g_option_context_new ("REV TARGETDIR"); + context = g_option_context_new ("REV_OR_DIR REV_OR_DIR"); if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) goto out; diff --git a/src/ostree/ot-builtin-find-remotes.c b/src/ostree/ot-builtin-find-remotes.c index f255501a..944533ca 100644 --- a/src/ostree/ot-builtin-find-remotes.c +++ b/src/ostree/ot-builtin-find-remotes.c @@ -35,6 +35,7 @@ static gchar *opt_cache_dir = NULL; static gchar *opt_finders = NULL; static gboolean opt_disable_fsync = FALSE; static gboolean opt_pull = FALSE; +static gboolean opt_mirror = FALSE; static GOptionEntry options[] = { @@ -42,6 +43,7 @@ static GOptionEntry options[] = { "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, { "finders", 0, 0, G_OPTION_ARG_STRING, &opt_finders, "Use the specified comma separated list of finders (e.g. config,lan,mount)", "FINDERS" }, { "pull", 0, 0, G_OPTION_ARG_NONE, &opt_pull, "Pull the updates after finding them", NULL }, + { "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Do a mirror pull (see ostree pull --mirror)", NULL}, { NULL } }; @@ -188,6 +190,7 @@ ostree_builtin_find_remotes (int argc, g_auto(OstreeRepoFinderResultv) results = NULL; g_auto(GLnxConsoleRef) console = { 0, }; g_autoptr(GHashTable) refs_found = NULL; /* set (element-type OstreeCollectionRef) */ + g_autoptr(GVariant) pull_options = NULL; context = g_option_context_new ("COLLECTION-ID REF [COLLECTION-ID REF...]"); @@ -210,6 +213,12 @@ ostree_builtin_find_remotes (int argc, return FALSE; } + if (opt_mirror && !opt_pull) + { + ot_util_usage_error (context, "When --mirror is specified, --pull must also be", error); + return FALSE; + } + if (opt_disable_fsync) ostree_repo_set_disable_fsync (repo, TRUE); @@ -359,13 +368,24 @@ ostree_builtin_find_remotes (int argc, if (!opt_pull) return TRUE; + { + GVariantBuilder builder; + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + + if (opt_mirror) + g_variant_builder_add (&builder, "{s@v}", "flags", + g_variant_new_variant (g_variant_new_int32 (OSTREE_REPO_PULL_FLAGS_MIRROR))); + + pull_options = g_variant_ref_sink (g_variant_builder_end (&builder)); + } + /* Run the pull operation. */ if (console.is_tty) progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console); ostree_repo_pull_from_remotes_async (repo, (const OstreeRepoFinderResult * const *) results, - NULL, /* no options */ + pull_options, progress, cancellable, get_result_cb, &pull_result); diff --git a/src/ostree/ot-builtin-pull-local.c b/src/ostree/ot-builtin-pull-local.c index 4b3224f3..43f4f255 100644 --- a/src/ostree/ot-builtin-pull-local.c +++ b/src/ostree/ot-builtin-pull-local.c @@ -34,6 +34,7 @@ static char *opt_remote; static gboolean opt_commit_only; static gboolean opt_disable_fsync; +static gboolean opt_per_object_fsync; static gboolean opt_untrusted; static gboolean opt_bareuseronly_files; static gboolean opt_require_static_deltas; @@ -50,6 +51,7 @@ static GOptionEntry options[] = { { "commit-metadata-only", 0, 0, G_OPTION_ARG_NONE, &opt_commit_only, "Fetch only the commit metadata", NULL }, { "remote", 0, 0, G_OPTION_ARG_STRING, &opt_remote, "Add REMOTE to refspec", "REMOTE" }, { "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, + { "per-object-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_per_object_fsync, "Perform writes in such a way that avoids stalling concurrent processes", NULL }, { "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Verify checksums of local sources (always enabled for HTTP pulls)", NULL }, { "bareuseronly-files", 0, 0, G_OPTION_ARG_NONE, &opt_bareuseronly_files, "Reject regular files with mode outside of 0775 (world writable, suid, etc.)", NULL }, { "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_require_static_deltas, "Require static deltas", NULL }, @@ -181,6 +183,16 @@ ostree_builtin_pull_local (int argc, char **argv, OstreeCommandInvocation *invoc g_variant_new_variant (g_variant_new_boolean (TRUE))); g_variant_builder_add (&builder, "{s@v}", "depth", g_variant_new_variant (g_variant_new_int32 (opt_depth))); + /* local pulls always disable signapi verification. If you don't want this, use + * ostree remote add --sign-verify= file:// + */ + g_variant_builder_add (&builder, "{s@v}", "disable-sign-verify", + g_variant_new_variant (g_variant_new_boolean (TRUE))); + g_variant_builder_add (&builder, "{s@v}", "disable-sign-verify-summary", + g_variant_new_variant (g_variant_new_boolean (TRUE))); + if (opt_per_object_fsync) + g_variant_builder_add (&builder, "{s@v}", "per-object-fsync", + g_variant_new_variant (g_variant_new_boolean (TRUE))); if (console.is_tty) progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console); diff --git a/src/ostree/ot-builtin-pull.c b/src/ostree/ot-builtin-pull.c index 1fae0a38..e69d62e3 100644 --- a/src/ostree/ot-builtin-pull.c +++ b/src/ostree/ot-builtin-pull.c @@ -29,6 +29,7 @@ #include "otutil.h" static gboolean opt_disable_fsync; +static gboolean opt_per_object_fsync; static gboolean opt_mirror; static gboolean opt_commit_only; static gboolean opt_dry_run; @@ -37,6 +38,7 @@ static gboolean opt_require_static_deltas; static gboolean opt_untrusted; static gboolean opt_http_trusted; static gboolean opt_timestamp_check; +static char* opt_timestamp_check_from_rev; static gboolean opt_bareuseronly_files; static char** opt_subpaths; static char** opt_http_headers; @@ -57,6 +59,7 @@ static GOptionEntry options[] = { { "commit-metadata-only", 0, 0, G_OPTION_ARG_NONE, &opt_commit_only, "Fetch only the commit metadata", NULL }, { "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL }, { "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, + { "per-object-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_per_object_fsync, "Perform writes in such a way that avoids stalling concurrent processes", NULL }, { "disable-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_disable_static_deltas, "Do not use static deltas", NULL }, { "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_require_static_deltas, "Require static deltas", NULL }, { "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Write refs suitable for a mirror and fetches all refs if none provided", NULL }, @@ -72,6 +75,7 @@ static GOptionEntry options[] = { { "network-retries", 0, 0, G_OPTION_ARG_INT, &opt_network_retries, "Specifies how many times each download should be retried upon error (default: 5)", "N"}, { "localcache-repo", 'L', 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_localcache_repos, "Add REPO as local cache source for objects during this pull", "REPO" }, { "timestamp-check", 'T', 0, G_OPTION_ARG_NONE, &opt_timestamp_check, "Require fetched commits to have newer timestamps", NULL }, + { "timestamp-check-from-rev", 0, 0, G_OPTION_ARG_STRING, &opt_timestamp_check_from_rev, "Require fetched commits to have newer timestamps than given rev", NULL }, /* let's leave this hidden for now; we just need it for tests */ { "append-user-agent", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &opt_append_user_agent, "Append string to user agent", NULL }, { NULL } @@ -313,6 +317,9 @@ ostree_builtin_pull (int argc, char **argv, OstreeCommandInvocation *invocation, if (opt_timestamp_check) g_variant_builder_add (&builder, "{s@v}", "timestamp-check", g_variant_new_variant (g_variant_new_boolean (opt_timestamp_check))); + if (opt_timestamp_check_from_rev) + g_variant_builder_add (&builder, "{s@v}", "timestamp-check-from-rev", + g_variant_new_variant (g_variant_new_string (opt_timestamp_check_from_rev))); if (override_commit_ids) g_variant_builder_add (&builder, "{s@v}", "override-commit-ids", @@ -320,7 +327,9 @@ ostree_builtin_pull (int argc, char **argv, OstreeCommandInvocation *invocation, if (opt_localcache_repos) g_variant_builder_add (&builder, "{s@v}", "localcache-repos", g_variant_new_variant (g_variant_new_strv ((const char*const*)opt_localcache_repos, -1))); - + if (opt_per_object_fsync) + g_variant_builder_add (&builder, "{s@v}", "per-object-fsync", + g_variant_new_variant (g_variant_new_boolean (TRUE))); if (opt_http_headers) { GVariantBuilder hdr_builder; diff --git a/src/ostree/ot-builtin-sign.c b/src/ostree/ot-builtin-sign.c new file mode 100644 index 00000000..c7777489 --- /dev/null +++ b/src/ostree/ot-builtin-sign.c @@ -0,0 +1,264 @@ +/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */ + +/* + * Copyright (C) 2015 Colin Walters + * Copyright (C) 2019 Denis Pynkin (d4s) + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" +#include "ostree-core-private.h" +#include "ostree-sign.h" + +static gboolean opt_delete; +static gboolean opt_verify; +static char *opt_sign_name; +static char *opt_filename; +static char *opt_keysdir; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-sign.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "delete", 'd', 0, G_OPTION_ARG_NONE, &opt_delete, "Delete signatures having any of the KEY-IDs", NULL}, + { "verify", 0, 0, G_OPTION_ARG_NONE, &opt_verify, "Verify signatures", NULL}, + { "sign-type", 's', 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME"}, +#if defined(HAVE_LIBSODIUM) + { "keys-file", 0, 0, G_OPTION_ARG_STRING, &opt_filename, "Read key(s) from file", "NAME"}, + { "keys-dir", 0, 0, G_OPTION_ARG_STRING, &opt_keysdir, "Redefine system-wide directories with public and revoked keys for verification", "NAME"}, +#endif + { NULL } +}; + +static void +usage_error (GOptionContext *context, const char *message, GError **error) +{ + g_autofree char *help = g_option_context_get_help (context, TRUE, NULL); + g_printerr ("%s", help); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, message); +} + +gboolean +ostree_builtin_sign (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr (GOptionContext) context = NULL; + g_autoptr (OstreeRepo) repo = NULL; + g_autoptr (OstreeSign) sign = NULL; + g_autofree char *resolved_commit = NULL; + g_autofree char *success_message = NULL; + const char *commit; + char **key_ids; + int n_key_ids, ii; + gboolean ret = FALSE; + + context = g_option_context_new ("COMMIT KEY-ID..."); + + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + goto out; + + if (argc < 2) + { + usage_error (context, "Need a COMMIT to sign or verify", error); + goto out; + } + + commit = argv[1]; + + /* Verification could be done via system files with public keys */ + if (!opt_verify && + !opt_filename && + argc < 3) + { + usage_error (context, "Need at least one KEY-ID to sign with", error); + goto out; + } + + key_ids = argv + 2; + n_key_ids = argc - 2; + + if (!ostree_repo_resolve_rev (repo, commit, FALSE, &resolved_commit, error)) + goto out; + + /* Initialize crypto system */ + opt_sign_name = opt_sign_name ?: OSTREE_SIGN_NAME_ED25519; + + sign = ostree_sign_get_by_name (opt_sign_name, error); + if (sign == NULL) + goto out; + + for (ii = 0; ii < n_key_ids; ii++) + { + g_autoptr (GVariant) sk = NULL; + g_autoptr (GVariant) pk = NULL; + + if (opt_verify) + { + g_autoptr (GError) local_error = NULL; + + + // Pass the key as a string + pk = g_variant_new_string(key_ids[ii]); + + if (!ostree_sign_set_pk (sign, pk, &local_error)) + continue; + + if (ostree_sign_commit_verify (sign, + repo, + resolved_commit, + &success_message, + cancellable, + &local_error)) + { + g_assert (success_message); + g_print ("%s\n", success_message); + ret = TRUE; + goto out; + } + } + else + { + // Pass the key as a string + sk = g_variant_new_string(key_ids[ii]); + if (!ostree_sign_set_sk (sign, sk, error)) + { + ret = FALSE; + goto out; + } + + ret = ostree_sign_commit (sign, + repo, + resolved_commit, + cancellable, + error); + if (ret != TRUE) + goto out; + } + } + + /* Try to verify with user-provided file or system configuration */ + if (opt_verify) + { + if ((n_key_ids == 0) || opt_filename) + { + g_autoptr (GVariantBuilder) builder = NULL; + g_autoptr (GVariant) options = NULL; + + builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + /* Use custom directory with public and revoked keys instead of system-wide directories */ + if (opt_keysdir) + g_variant_builder_add (builder, "{sv}", "basedir", g_variant_new_string (opt_keysdir)); + /* The last chance for verification source -- system files */ + if (opt_filename) + g_variant_builder_add (builder, "{sv}", "filename", g_variant_new_string (opt_filename)); + options = g_variant_builder_end (builder); + + if (!ostree_sign_load_pk (sign, options, error)) + goto out; + + if (ostree_sign_commit_verify (sign, + repo, + resolved_commit, + &success_message, + cancellable, + error)) + { + g_print ("%s\n", success_message); + ret = TRUE; + } + } /* Check via file */ + } + else + { + /* Sign with keys from provided file */ + if (opt_filename) + { + g_autoptr (GFile) keyfile = NULL; + g_autoptr (GFileInputStream) key_stream_in = NULL; + g_autoptr (GDataInputStream) key_data_in = NULL; + + if (!g_file_test (opt_filename, G_FILE_TEST_IS_REGULAR)) + { + g_warning ("Can't open file '%s' with keys", opt_filename); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "File object '%s' is not a regular file", opt_filename); + goto out; + } + + keyfile = g_file_new_for_path (opt_filename); + key_stream_in = g_file_read (keyfile, NULL, error); + if (key_stream_in == NULL) + goto out; + + key_data_in = g_data_input_stream_new (G_INPUT_STREAM(key_stream_in)); + g_assert (key_data_in != NULL); + + /* Use simple file format with just a list of base64 public keys per line */ + while (TRUE) + { + gsize len = 0; + g_autofree char *line = g_data_input_stream_read_line (key_data_in, &len, NULL, error); + g_autoptr (GVariant) sk = NULL; + + if (*error != NULL) + goto out; + + if (line == NULL) + break; + + + // Pass the key as a string + sk = g_variant_new_string(line); + if (!ostree_sign_set_sk (sign, sk, error)) + { + ret = FALSE; + goto out; + } + + ret = ostree_sign_commit (sign, + repo, + resolved_commit, + cancellable, + error); + if (ret != TRUE) + goto out; + } + } + } + // No valid signature found + if (opt_verify && (ret != TRUE) && (*error == NULL)) + g_set_error_literal (error, + G_IO_ERROR, G_IO_ERROR_FAILED, + "No valid signatures found"); + +out: + /* It is possible to have an error due multiple signatures check */ + if (ret == TRUE) + g_clear_error (error); + return ret; +} diff --git a/src/ostree/ot-builtin-summary.c b/src/ostree/ot-builtin-summary.c index 0f70f071..0938f11e 100644 --- a/src/ostree/ot-builtin-summary.c +++ b/src/ostree/ot-builtin-summary.c @@ -27,10 +27,13 @@ #include "ot-builtins.h" #include "ostree.h" #include "otutil.h" +#include "ostree-sign.h" static gboolean opt_update, opt_view, opt_raw; -static char **opt_key_ids; +static char **opt_gpg_key_ids; static char *opt_gpg_homedir; +static char **opt_key_ids; +static char *opt_sign_name; static char **opt_metadata; /* ATTENTION: @@ -42,8 +45,10 @@ static GOptionEntry options[] = { { "update", 'u', 0, G_OPTION_ARG_NONE, &opt_update, "Update the summary", NULL }, { "view", 'v', 0, G_OPTION_ARG_NONE, &opt_view, "View the local summary file", NULL }, { "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "View the raw bytes of the summary file", NULL }, - { "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the summary with", "KEY-ID"}, + { "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_gpg_key_ids, "GPG Key ID to sign the summary with", "KEY-ID"}, { "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"}, + { "sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "Key ID to sign the summary with", "KEY-ID"}, + { "sign-type", 0, 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME"}, { "add-metadata", 'm', 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata, "Additional metadata field to add to the summary", "KEY=VALUE" }, { NULL } }; @@ -87,6 +92,7 @@ ostree_builtin_summary (int argc, char **argv, OstreeCommandInvocation *invocati { g_autoptr(GOptionContext) context = NULL; g_autoptr(OstreeRepo) repo = NULL; + g_autoptr (OstreeSign) sign = NULL; OstreeDumpFlags flags = OSTREE_DUMP_NONE; context = g_option_context_new (""); @@ -94,6 +100,16 @@ ostree_builtin_summary (int argc, char **argv, OstreeCommandInvocation *invocati if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) return FALSE; + /* Initialize crypto system */ + if (opt_key_ids) + { + opt_sign_name = opt_sign_name ?: OSTREE_SIGN_NAME_ED25519; + + sign = ostree_sign_get_by_name (opt_sign_name, error); + if (sign == NULL) + return FALSE; + } + if (opt_update) { g_autoptr(GVariant) additional_metadata = NULL; @@ -164,10 +180,9 @@ ostree_builtin_summary (int argc, char **argv, OstreeCommandInvocation *invocati new_summary_commit, repo_file, &new_ostree_metadata_checksum, NULL, error)) return FALSE; - - if (opt_key_ids != NULL) + if (opt_gpg_key_ids != NULL) { - for (const char * const *iter = (const char * const *) opt_key_ids; + for (const char * const *iter = (const char * const *) opt_gpg_key_ids; iter != NULL && *iter != NULL; iter++) { const char *key_id = *iter; @@ -182,6 +197,27 @@ ostree_builtin_summary (int argc, char **argv, OstreeCommandInvocation *invocati } } + if (opt_key_ids) + { + char **iter; + for (iter = opt_key_ids; iter && *iter; iter++) + { + const char *keyid = *iter; + g_autoptr (GVariant) secret_key = NULL; + + secret_key = g_variant_new_string (keyid); + if (!ostree_sign_set_sk (sign, secret_key, error)) + return FALSE; + + if (!ostree_sign_commit (sign, + repo, + new_ostree_metadata_checksum, + cancellable, + error)) + return FALSE; + } + } + ostree_repo_transaction_set_collection_ref (repo, &collection_ref, new_ostree_metadata_checksum); @@ -194,16 +230,45 @@ ostree_builtin_summary (int argc, char **argv, OstreeCommandInvocation *invocati return FALSE; #ifndef OSTREE_DISABLE_GPGME - if (opt_key_ids) + if (opt_gpg_key_ids) { if (!ostree_repo_add_gpg_signature_summary (repo, - (const gchar **) opt_key_ids, + (const gchar **) opt_gpg_key_ids, opt_gpg_homedir, cancellable, error)) return FALSE; } #endif + if (opt_key_ids) + { + g_autoptr (GVariant) secret_keys = NULL; + g_autoptr (GVariantBuilder) sk_builder = NULL; + + sk_builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY); + + char **iter; + for (iter = opt_key_ids; iter && *iter; iter++) + { + const char *keyid = *iter; + GVariant *secret_key = NULL; + + /* Currently only strings are used as keys + * for supported signature types */ + secret_key = g_variant_new_string (keyid); + + g_variant_builder_add (sk_builder, "v", secret_key); + } + + secret_keys = g_variant_builder_end (sk_builder); + + if (! ostree_sign_summary (sign, + repo, + secret_keys, + cancellable, + error)) + return FALSE; + } } else if (opt_view || opt_raw) { diff --git a/src/ostree/ot-builtins.h b/src/ostree/ot-builtins.h index 12a99b45..e372d359 100644 --- a/src/ostree/ot-builtins.h +++ b/src/ostree/ot-builtins.h @@ -53,6 +53,7 @@ BUILTINPROTO(prune); BUILTINPROTO(refs); BUILTINPROTO(reset); BUILTINPROTO(fsck); +BUILTINPROTO(sign); BUILTINPROTO(show); BUILTINPROTO(static_delta); BUILTINPROTO(summary); diff --git a/src/ostree/ot-remote-builtin-add.c b/src/ostree/ot-remote-builtin-add.c index cea0b274..172625d2 100644 --- a/src/ostree/ot-remote-builtin-add.c +++ b/src/ostree/ot-remote-builtin-add.c @@ -28,9 +28,11 @@ static char **opt_set; static gboolean opt_no_gpg_verify; +static gboolean opt_no_sign_verify; static gboolean opt_if_not_exists; static gboolean opt_force; static char *opt_gpg_import; +static char **opt_sign_verify; static char *opt_contenturl; static char *opt_collection_id; static char *opt_sysroot; @@ -44,6 +46,8 @@ static char *opt_repo; static GOptionEntry option_entries[] = { { "set", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_set, "Set config option KEY=VALUE for remote", "KEY=VALUE" }, { "no-gpg-verify", 0, 0, G_OPTION_ARG_NONE, &opt_no_gpg_verify, "Disable GPG verification", NULL }, + { "no-sign-verify", 0, 0, G_OPTION_ARG_NONE, &opt_no_sign_verify, "Disable signature verification", NULL }, + { "sign-verify", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_sign_verify, "Verify signatures using KEYTYPE=inline:PUBKEY or KEYTYPE=file:/path/to/key", "KEYTYPE=[inline|file]:PUBKEY" }, { "if-not-exists", 0, 0, G_OPTION_ARG_NONE, &opt_if_not_exists, "Do nothing if the provided remote exists", NULL }, { "force", 0, 0, G_OPTION_ARG_NONE, &opt_force, "Replace the provided remote if it exists", NULL }, { "gpg-import", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_import, "Import GPG key from FILE", "FILE" }, @@ -55,12 +59,49 @@ static GOptionEntry option_entries[] = { { NULL } }; +static char * +add_verify_opt (GVariantBuilder *builder, + const char *keyspec, + GError **error) +{ + g_auto(GStrv) parts = g_strsplit (keyspec, "=", 2); + g_assert (parts && *parts); + const char *keytype = parts[0]; + if (!parts[1]) + return glnx_null_throw (error, "Failed to parse KEYTYPE=[inline|file]:DATA in %s", keyspec); + + g_autoptr(OstreeSign) sign = ostree_sign_get_by_name (keytype, error); + if (!sign) + return NULL; + + const char *rest = parts[1]; + g_assert (!parts[2]); + g_auto(GStrv) keyparts = g_strsplit (rest, ":", 2); + g_assert (keyparts && *keyparts); + const char *keyref = keyparts[0]; + g_assert (keyref); + g_autofree char *optname = NULL; + if (g_str_equal (keyref, "inline")) + optname = g_strdup_printf ("verification-%s-key", keytype); + else if (g_str_equal (keyref, "file")) + optname = g_strdup_printf ("verification-%s-file", keytype); + else + return glnx_null_throw (error, "Invalid key reference %s, expected inline|file", keyref); + + g_assert (keyparts[1] && !keyparts[2]); + g_variant_builder_add (builder, "{s@v}", + optname, + g_variant_new_variant (g_variant_new_string (keyparts[1]))); + return g_strdup (ostree_sign_get_name (sign)); +} + gboolean ot_remote_builtin_add (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; g_autoptr(OstreeSysroot) sysroot = NULL; g_autoptr(OstreeRepo) repo = NULL; + g_autoptr(GString) sign_verify = NULL; const char *remote_name; const char *remote_url; char **iter; @@ -134,12 +175,43 @@ ot_remote_builtin_add (int argc, char **argv, OstreeCommandInvocation *invocatio } #ifndef OSTREE_DISABLE_GPGME - if (opt_no_gpg_verify) + /* No signature verification implies no verification for GPG signature as well */ + if (opt_no_gpg_verify || opt_no_sign_verify) g_variant_builder_add (optbuilder, "{s@v}", "gpg-verify", g_variant_new_variant (g_variant_new_boolean (FALSE))); #endif /* OSTREE_DISABLE_GPGME */ + if (opt_no_sign_verify) + { + if (opt_sign_verify) + return glnx_throw (error, "Cannot specify both --sign-verify and --no-sign-verify"); + g_variant_builder_add (optbuilder, "{s@v}", + "sign-verify", + g_variant_new_variant (g_variant_new_boolean (FALSE))); + } + + for (char **iter = opt_sign_verify; iter && *iter; iter++) + { + const char *keyspec = *iter; + g_autofree char *signname = add_verify_opt (optbuilder, keyspec, error); + if (!signname) + return FALSE; + if (!sign_verify) + { + sign_verify = g_string_new (signname); + } + else + { + g_string_append_c (sign_verify, ','); + g_string_append (sign_verify, signname); + } + } + if (sign_verify != NULL) + g_variant_builder_add (optbuilder, "{s@v}", + "sign-verify", + g_variant_new_variant (g_variant_new_string (sign_verify->str))); + if (opt_collection_id != NULL) g_variant_builder_add (optbuilder, "{s@v}", "collection-id", g_variant_new_variant (g_variant_new_take_string (g_steal_pointer (&opt_collection_id)))); diff --git a/src/switchroot/ostree-mount-util.h b/src/switchroot/ostree-mount-util.h index 0b40bb40..fb2d02b4 100644 --- a/src/switchroot/ostree-mount-util.h +++ b/src/switchroot/ostree-mount-util.h @@ -30,11 +30,13 @@ #include #include #include +#include #define INITRAMFS_MOUNT_VAR "/run/ostree/initramfs-mount-var" +#define _OSTREE_SYSROOT_READONLY_STAMP "/run/ostree-sysroot-ro.stamp" static inline int -path_is_on_readonly_fs (char *path) +path_is_on_readonly_fs (const char *path) { struct statvfs stvfsbuf; diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c index c25d3fe9..8a68e1f4 100644 --- a/src/switchroot/ostree-prepare-root.c +++ b/src/switchroot/ostree-prepare-root.c @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +84,47 @@ /* Initialized early in main */ static bool running_as_pid1; +static inline bool +sysroot_is_configured_ro (const char *sysroot) +{ + char * config_path = NULL; + assert (asprintf (&config_path, "%s/ostree/repo/config", sysroot) != -1); + FILE *f = fopen(config_path, "r"); + if (!f) + { + fprintf (stderr, "Missing expected repo config: %s\n", config_path); + free (config_path); + return false; + } + free (config_path); + + bool ret = false; + char *line = NULL; + size_t len = 0; + ssize_t nread; + /* Note getline() will reuse the previous buffer */ + bool in_sysroot = false; + while ((nread = getline (&line, &len, f)) != -1) + { + /* This is an awful hack to avoid depending on GLib in the + * initramfs right now. + */ + if (strstr (line, "[sysroot]") == line) + in_sysroot = true; + else if (*line == '[') + in_sysroot = false; + else if (in_sysroot && strstr (line, "readonly=true") == line) + { + ret = true; + break; + } + } + + fclose (f); + free (line); + return ret; +} + static char* resolve_deploy_path (const char * root_mountpoint) { @@ -192,6 +234,33 @@ main(int argc, char *argv[]) if (chdir (deploy_path) < 0) err (EXIT_FAILURE, "failed to chdir to deploy_path"); + /* Query the repository configuration - this is an operating system builder + * choice. More info: https://github.com/ostreedev/ostree/pull/1767 + */ + const bool sysroot_readonly = sysroot_is_configured_ro (root_arg); + const bool sysroot_currently_writable = !path_is_on_readonly_fs (root_arg); + +#ifdef USE_LIBSYSTEMD + sd_journal_send ("MESSAGE=sysroot configured read-only: %d, currently writable: %d", + (int)sysroot_readonly, (int)sysroot_currently_writable, NULL); +#endif + if (sysroot_readonly) + { + if (!sysroot_currently_writable) + errx (EXIT_FAILURE, "sysroot=readonly currently requires writable / in initramfs"); + /* Now, /etc is not normally a bind mount, but if we have a readonly + * sysroot, we still need a writable /etc. And to avoid race conditions + * we ensure it's writable in the initramfs, before we switchroot at all. + */ + if (mount ("/etc", "/etc", NULL, MS_BIND, NULL) < 0) + err (EXIT_FAILURE, "failed to make /etc a bind mount"); + /* Pass on the fact that we discovered a readonly sysroot to ostree-remount.service */ + int fd = open (_OSTREE_SYSROOT_READONLY_STAMP, O_WRONLY | O_CREAT | O_CLOEXEC, 0644); + if (fd < 0) + err (EXIT_FAILURE, "failed to create %s", _OSTREE_SYSROOT_READONLY_STAMP); + (void) close (fd); + } + /* Default to true, but in the systemd case, default to false because it's handled by * ostree-system-generator. */ bool mount_var = true; diff --git a/src/switchroot/ostree-remount.c b/src/switchroot/ostree-remount.c index 326b104f..5c313c87 100644 --- a/src/switchroot/ostree-remount.c +++ b/src/switchroot/ostree-remount.c @@ -81,21 +81,6 @@ do_remount (const char *target, printf ("Remounted %s: %s\n", writable ? "rw" : "ro", target); } -static bool -sysroot_is_configured_ro (void) -{ - struct stat stbuf; - static const char config_path[] = "/ostree/repo/config"; - if (stat (config_path, &stbuf) != 0) - return false; - - g_autoptr(GKeyFile) keyfile = g_key_file_new (); - if (!g_key_file_load_from_file (keyfile, config_path, 0, NULL)) - return false; - - return g_key_file_get_boolean (keyfile, "sysroot", "readonly", NULL); -} - int main(int argc, char *argv[]) { @@ -121,25 +106,10 @@ main(int argc, char *argv[]) exit (EXIT_SUCCESS); } - /* Query the repository configuration - this is an operating system builder - * choice. - * */ - const bool sysroot_readonly = sysroot_is_configured_ro (); - - /* Mount the sysroot read-only if we're configured to do so. - * Note we only get here if / is already writable. - */ - do_remount ("/sysroot", !sysroot_readonly); - - if (sysroot_readonly) + /* Handle remounting /sysroot read-only now */ + if (unlink (_OSTREE_SYSROOT_READONLY_STAMP) == 0) { - /* Now, /etc is not normally a bind mount, but remounting the - * sysroot above made it read-only since it's on the same filesystem. - * Make it a self-bind mount, so we can then mount it read-write. - */ - if (mount ("/etc", "/etc", NULL, MS_BIND, NULL) < 0) - err (EXIT_FAILURE, "failed to make /etc a bind mount"); - do_remount ("/etc", true); + do_remount ("/sysroot", false); } /* If /var was created as as an OSTree default bind mount (instead of being a separate filesystem) diff --git a/tests/admin-test.sh b/tests/admin-test.sh index 11b9ea14..3aab74cc 100644 --- a/tests/admin-test.sh +++ b/tests/admin-test.sh @@ -21,7 +21,7 @@ set -euo pipefail -echo "1..$((27 + ${extra_admin_tests:-0}))" +echo "1..$((28 + ${extra_admin_tests:-0}))" mkdir sysrootmin ${CMD_PREFIX} ostree admin init-fs --modern sysrootmin @@ -300,19 +300,48 @@ echo "ok no duplicate version strings in title" # Test upgrade with and without --override-commit # See https://github.com/GNOME/ostree/pull/147 -${CMD_PREFIX} ostree pull --repo=sysroot/ostree/repo --commit-metadata-only --depth=-1 testos:testos/buildmaster/x86_64-runtime -head_rev=$(${CMD_PREFIX} ostree rev-parse --repo=sysroot/ostree/repo testos/buildmaster/x86_64-runtime) -prev_rev=$(${CMD_PREFIX} ostree rev-parse --repo=sysroot/ostree/repo testos/buildmaster/x86_64-runtime^^^^) -assert_not_streq ${head_rev} ${prev_rev} -${CMD_PREFIX} ostree admin upgrade --os=testos --override-commit=${prev_rev} --allow-downgrade -curr_rev=$(${CMD_PREFIX} ostree rev-parse --repo=sysroot/ostree/repo testos/buildmaster/x86_64-runtime) -assert_streq ${curr_rev} ${prev_rev} +sleep 1 +os_repository_new_commit +# upgrade to the latest ${CMD_PREFIX} ostree admin upgrade --os=testos -curr_rev=$(${CMD_PREFIX} ostree rev-parse --repo=sysroot/ostree/repo testos/buildmaster/x86_64-runtime) -assert_streq ${curr_rev} ${head_rev} +head_rev=$(${CMD_PREFIX} ostree rev-parse --repo=sysroot/ostree/repo testos/buildmaster/x86_64-runtime) +prev_rev=$(${CMD_PREFIX} ostree rev-parse --repo=sysroot/ostree/repo testos/buildmaster/x86_64-runtime^) +assert_not_streq ${head_rev} ${prev_rev} +# Don't use `ostree admin status | head -n 1` directly here because `head` +# exiting early might cause SIGPIPE to ostree, which with `set -euo pipefail` +# will cause us to exit. See: https://github.com/ostreedev/ostree/pull/2110. +${CMD_PREFIX} ostree admin status > status-out.txt +head -n 1 < status-out.txt > status.txt +assert_file_has_content status.txt ".* testos ${head_rev}.*" +# now, check that we can't downgrade to an older commit without --allow-downgrade +if ${CMD_PREFIX} ostree admin upgrade --os=testos --override-commit=${prev_rev} 2> err.txt; then + cat err.txt + fatal "downgraded without --allow-downgrade?" +fi +assert_file_has_content err.txt "Upgrade.*is chronologically older" +${CMD_PREFIX} ostree admin upgrade --os=testos --override-commit=${prev_rev} --allow-downgrade +${CMD_PREFIX} ostree admin status > status-out.txt +head -n 1 < status-out.txt > status.txt +assert_file_has_content status.txt ".* testos ${prev_rev}.*" +${CMD_PREFIX} ostree admin upgrade --os=testos +${CMD_PREFIX} ostree admin status > status-out.txt +head -n 1 < status-out.txt > status.txt +assert_file_has_content status.txt ".* testos ${head_rev}.*" echo "ok upgrade with and without override-commit" +# check that we can still upgrade to a rev that's not the tip of the branch but +# that's still newer than the deployment +sleep 1 +os_repository_new_commit +sleep 1 +os_repository_new_commit +${CMD_PREFIX} ostree pull --repo=sysroot/ostree/repo --commit-metadata-only --depth=-1 testos:testos/buildmaster/x86_64-runtime +curr_rev=$(${CMD_PREFIX} ostree rev-parse --repo=sysroot/ostree/repo testos/buildmaster/x86_64-runtime) +prev_rev=$(${CMD_PREFIX} ostree rev-parse --repo=sysroot/ostree/repo testos/buildmaster/x86_64-runtime^) +${CMD_PREFIX} ostree admin upgrade --os=testos --override-commit=${prev_rev} +echo "ok upgrade to newer version older than branch tip" + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string "version=${version}" \ --add-metadata-string 'ostree.source-title=libtest os_repository_new_commit()' -b testos/buildmaster/x86_64-runtime \ -s "Build" --tree=dir=${test_tmpdir}/osdata diff --git a/tests/archive-test.sh b/tests/archive-test.sh index 42b232bf..1e63a35b 100644 --- a/tests/archive-test.sh +++ b/tests/archive-test.sh @@ -68,3 +68,11 @@ echo "ok cat-file" cd ${test_tmpdir} $OSTREE fsck echo "ok fsck" + +mkdir -p test-overlays +date > test-overlays/overlaid-file +$OSTREE commit ${COMMIT_ARGS} -b test-base --base test2 --owner-uid 42 --owner-gid 42 test-overlays/ +$OSTREE ls -R test-base > ls.txt +assert_streq "$(wc -l < ls.txt)" 14 +assert_streq "$(grep '42.*42' ls.txt | wc -l)" 2 +echo "ok commit overlay base" diff --git a/tests/basic-test.sh b/tests/basic-test.sh index ba88cc73..fc193f4f 100644 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -21,7 +21,7 @@ set -euo pipefail -echo "1..$((88 + ${extra_basic_tests:-0}))" +echo "1..$((86 + ${extra_basic_tests:-0}))" CHECKOUT_U_ARG="" CHECKOUT_H_ARGS="-H" @@ -541,6 +541,24 @@ fi assert_file_has_mode checkout-test2-override/a/readable-only 600 echo "ok commit statoverride" +cd ${test_tmpdir} +rm test2-checkout -rf +$OSTREE checkout test2 test2-checkout +cd test2-checkout +install -m 0755 /dev/null user-wx +install -m 0575 /dev/null group-wx +install -m 0775 /dev/null both-wx +install -m 0555 /dev/null ugox +install -m 0644 /dev/null user-writable +cd .. +$OSTREE commit ${COMMIT_ARGS} -b test2-w-xor-x --mode-ro-executables --tree=dir=test2-checkout +$OSTREE ls test2-w-xor-x > ls.txt +for x in /{user,group,both}-wx; do + assert_file_has_content ls.txt '^-00555 .*'$x +done +assert_file_has_content ls.txt '^-00644 .*/user-writable' +echo "ok commit --mode-ro-executables" + cd ${test_tmpdir} cat > test-skiplist.txt < deeper-mtime assert_file_has_content deeper-mtime 0 echo "ok content mtime" -cd ${test_tmpdir} -rm -rf test2-checkout -mkdir -p test2-checkout -cd test2-checkout -mkfifo afifo -if $OSTREE commit ${COMMIT_ARGS} -b test2 -s "Attempt to commit a FIFO" 2>../errmsg; then - assert_not_reached "Committing a FIFO unexpetedly succeeded!" - assert_file_has_content ../errmsg "Unsupported file type" -fi -echo "ok commit of fifo was rejected" - cd ${test_tmpdir} rm repo2 -rf mkdir repo2 @@ -1162,22 +1169,3 @@ if test "$(id -u)" != "0"; then else echo "ok # SKIP not run when root" fi - -cd ${test_tmpdir} -rm -rf test2-checkout -mkdir -p test2-checkout -cd test2-checkout -touch blah -stat --printf="%.Y\n" ${test_tmpdir}/repo > ${test_tmpdir}/timestamp-orig.txt -$OSTREE commit ${COMMIT_ARGS} -b test2 -s "Should bump the mtime" -stat --printf="%.Y\n" ${test_tmpdir}/repo > ${test_tmpdir}/timestamp-new.txt -cd .. -if cmp timestamp-{orig,new}.txt; then - assert_not_reached "failed to update mtime on repo" -fi -echo "ok mtime updated" - -cd ${test_tmpdir} -$OSTREE init --mode=bare --repo=repo-extensions -assert_has_dir repo-extensions/extensions -echo "ok extensions dir" diff --git a/tests/libtest-core.sh b/tests/libtest-core.sh index 945d2857..64b3e0a3 100644 --- a/tests/libtest-core.sh +++ b/tests/libtest-core.sh @@ -115,6 +115,16 @@ assert_file_has_content () { done } +assert_file_has_content_once () { + fpath=$1 + shift + for re in "$@"; do + if ! test $(grep -e "$re" "$fpath" | wc -l) = "1"; then + _fatal_print_file "$fpath" "File '$fpath' doesn't match regexp '$re' exactly once" + fi + done +} + assert_file_has_content_literal () { fpath=$1; shift for s in "$@"; do diff --git a/tests/libtest.sh b/tests/libtest.sh index c82bf487..ca457fa2 100755 --- a/tests/libtest.sh +++ b/tests/libtest.sh @@ -488,6 +488,11 @@ EOF cd ${oldpwd} } +timestamp_of_commit() +{ + date --date="$(ostree --repo=$1 show $2 | grep -Ee '^Date: ' | sed -e 's,^Date: *,,')" '+%s' +} + os_repository_new_commit () { boot_checksum_iteration=${1:-0} @@ -529,6 +534,13 @@ os_repository_new_commit () echo "content iteration ${content_iteration}" > usr/bin/content-iteration ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string "version=${version}" -b $branch -s "Build" + if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo rev-parse ${branch} 2>/dev/null; then + prevdate=$(timestamp_of_commit ${test_tmpdir}/testos-repo "${branch}"^) + newdate=$(timestamp_of_commit ${test_tmpdir}/testos-repo "${branch}") + if [ $((${prevdate} > ${newdate})) = 1 ]; then + fatal "clock skew detected writing commits: prev=${prevdate} new=${newdate}" + fi + fi cd ${test_tmpdir} } @@ -679,6 +691,43 @@ libtest_cleanup_gpg () { } libtest_exit_cmds+=(libtest_cleanup_gpg) +has_sign_ed25519 () { + local ret + ${CMD_PREFIX} ostree --version > version.txt + grep -q -e '- sign-ed25519' version.txt + ret=$? + rm -f version.txt + return ${ret} +} + +# Keys for ed25519 signing tests +ED25519PUBLIC= +ED25519SEED= +ED25519SECRET= + +gen_ed25519_keys () +{ + # Generate private key in PEM format + pemfile="$(mktemp -p ${test_tmpdir} ed25519_XXXXXX.pem)" + openssl genpkey -algorithm ed25519 -outform PEM -out "${pemfile}" + + # Based on: http://openssl.6102.n7.nabble.com/ed25519-key-generation-td73907.html + # Extract the private and public parts from generated key. + ED25519PUBLIC="$(openssl pkey -outform DER -pubout -in ${pemfile} | tail -c 32 | base64)" + ED25519SEED="$(openssl pkey -outform DER -in ${pemfile} | tail -c 32 | base64)" + # Secret key is concantination of SEED and PUBLIC + ED25519SECRET="$(echo ${ED25519SEED}${ED25519PUBLIC} | base64 -d | base64 -w 0)" + + echo "Generated ed25519 keys:" + echo "public: ${ED25519PUBLIC}" + echo " seed: ${ED25519SEED}" +} + +gen_ed25519_random_public() +{ + openssl genpkey -algorithm ED25519 | openssl pkey -outform DER | tail -c 32 | base64 +} + is_bare_user_only_repo () { grep -q 'mode=bare-user-only' $1/config } diff --git a/tests/pre-signed-pull-data.tar.gz b/tests/pre-signed-pull-data.tar.gz new file mode 100644 index 00000000..53a6019a Binary files /dev/null and b/tests/pre-signed-pull-data.tar.gz differ diff --git a/tests/pull-test.sh b/tests/pull-test.sh index 2cfd8e02..082ed315 100644 --- a/tests/pull-test.sh +++ b/tests/pull-test.sh @@ -29,7 +29,7 @@ function repo_init() { ${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo "$@" } -repo_init --no-gpg-verify +repo_init --no-sign-verify # See also the copy of this in basic-test.sh COMMIT_ARGS="" @@ -55,16 +55,16 @@ function verify_initial_contents() { } if has_gpgme; then - echo "1..34" + echo "1..35" else # 3 tests needs GPG support - echo "1..31" + echo "1..32" fi # Try both syntaxes -repo_init --no-gpg-verify +repo_init --no-sign-verify ${CMD_PREFIX} ostree --repo=repo pull origin main >out.txt -assert_file_has_content out.txt "[1-9][0-9]* metadata, [1-9][0-9]* content objects fetched" +assert_file_has_content out.txt "[1-9][0-9]* metadata, [1-9][0-9]* content objects fetched; [1-9][0-9]*.*written" ${CMD_PREFIX} ostree --repo=repo pull origin:main > out.txt assert_not_file_has_content out.txt "[1-9][0-9]* content objects fetched" ${CMD_PREFIX} ostree --repo=repo fsck @@ -74,6 +74,16 @@ cd ${test_tmpdir} verify_initial_contents echo "ok pull contents" +# And a test with incremental fsync +repo_init --no-sign-verify +${CMD_PREFIX} ostree --repo=repo pull --per-object-fsync origin main >out.txt +assert_file_has_content out.txt "[1-9][0-9]* metadata, [1-9][0-9]* content objects fetched" +${CMD_PREFIX} ostree --repo=repo pull --per-object-fsync origin:main > out.txt +assert_not_file_has_content out.txt "[1-9][0-9]* content objects fetched" +${CMD_PREFIX} ostree --repo=repo fsck +verify_initial_contents +echo "ok pull --per-object-fsync" + cd ${test_tmpdir} mkdir mirrorrepo ostree_repo_init mirrorrepo --mode=archive @@ -164,7 +174,7 @@ echo "ok pull (bareuseronly mirror)" # Corruption tests cd ${test_tmpdir} -repo_init --no-gpg-verify +repo_init --no-sign-verify if ! is_bare_user_only_repo repo; then if ! skip_one_without_user_xattrs; then if is_bare_user_only_repo repo; then @@ -216,7 +226,7 @@ if ! skip_one_without_user_xattrs; then done # And ensure the repo is reinitialized - repo_init --no-gpg-verify + repo_init --no-sign-verify echo "ok corruption" fi else @@ -318,9 +328,9 @@ ${CMD_PREFIX} ostree --repo=parentpullrepo rev-parse origin:main > main.txt assert_file_has_content main.txt ${rev} echo "ok pull specific commit" -# test pull -T +# test pull -T and --timestamp-check-from-rev cd ${test_tmpdir} -repo_init --no-gpg-verify +repo_init --no-sign-verify ${CMD_PREFIX} ostree --repo=repo pull origin main origrev=$(${CMD_PREFIX} ostree --repo=repo rev-parse main) # Check we can pull the same commit with timestamp checking enabled @@ -347,10 +357,32 @@ assert_file_has_content err.txt "Upgrade.*is chronologically older" assert_streq ${newrev} "$(${CMD_PREFIX} ostree --repo=repo rev-parse main)" # But we can pull it without timestamp checking ${CMD_PREFIX} ostree --repo=repo pull origin main +# Now test --timestamp-check-from-rev. First, add two new commits with distinct +# but newer timestamps. +oldrev=${newrev2} +middlerev=$(${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit ${COMMIT_ARGS} -b main --tree=ref=main) +sleep 1 +latestrev=$(${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit ${COMMIT_ARGS} -b main --tree=ref=main) +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +# OK, let's pull the latest now. +${CMD_PREFIX} ostree --repo=repo pull -T origin main +assert_streq ${latestrev} "$(${CMD_PREFIX} ostree --repo=repo rev-parse main)" +# Check we can't pull the middle commit by overrides with ts checking on +if ${CMD_PREFIX} ostree --repo=repo pull -T origin main@${middlerev} 2>err.txt; then + fatal "pulled older commit override with timestamp checking enabled?" +fi +assert_file_has_content err.txt "Upgrade.*is chronologically older" +# Check we can't pull an older commit by override if it's newer than --timestamp-check-from-rev +if ${CMD_PREFIX} ostree --repo=repo pull --timestamp-check-from-rev=${latestrev} origin main@${middlerev} 2>err.txt; then + fatal "pulled older commit override with timestamp checking enabled?" +fi +assert_file_has_content err.txt "Upgrade.*is chronologically older" +# But we can pull it with --timestamp-check-from-rev when starting from the oldrev +${CMD_PREFIX} ostree --repo=repo pull --timestamp-check-from-rev=${oldrev} origin main@${middlerev} echo "ok pull timestamp checking" cd ${test_tmpdir} -repo_init --no-gpg-verify +repo_init --no-sign-verify ${CMD_PREFIX} ostree --repo=repo pull origin main ${CMD_PREFIX} ostree --repo=repo fsck # Generate a delta from old to current, even though we aren't going to @@ -375,7 +407,7 @@ ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u # Explicitly test delta fetches via ref name as well as commit hash for delta_target in main ${new_rev}; do cd ${test_tmpdir} -repo_init --no-gpg-verify +repo_init --no-sign-verify ${CMD_PREFIX} ostree --repo=repo pull origin main@${prev_rev} ${CMD_PREFIX} ostree --repo=repo pull --dry-run --require-static-deltas origin ${delta_target} >dry-run-pull.txt # Compression can vary, so we support 400-699 @@ -388,7 +420,7 @@ done # Test pull via file:/// - this should still use the deltas path for testing cd ${test_tmpdir} -repo_init --no-gpg-verify +repo_init --no-sign-verify ${CMD_PREFIX} ostree --repo=repo remote delete origin ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin file://$(pwd)/ostree-srv/gnomerepo ${CMD_PREFIX} ostree --repo=repo pull origin main@${prev_rev} @@ -400,7 +432,7 @@ echo "ok pull file:// + deltas required" # Explicitly test delta fetches via ref name as well as commit hash for delta_target in main ${new_rev}; do cd ${test_tmpdir} -repo_init --no-gpg-verify +repo_init --no-sign-verify ${CMD_PREFIX} ostree --repo=repo pull origin main@${prev_rev} ${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin ${delta_target} if test ${delta_target} = main; then @@ -414,12 +446,12 @@ done # Test no-op with deltas: https://github.com/ostreedev/ostree/issues/1321 cd ${test_tmpdir} -repo_init --no-gpg-verify +repo_init --no-sign-verify ${CMD_PREFIX} ostree --repo=repo pull origin main ${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin main cd ${test_tmpdir} -repo_init --no-gpg-verify +repo_init --no-sign-verify ${CMD_PREFIX} ostree --repo=repo pull origin main@${prev_rev} ${CMD_PREFIX} ostree --repo=repo pull --disable-static-deltas origin main ${CMD_PREFIX} ostree --repo=repo fsck @@ -437,7 +469,7 @@ cd ${test_tmpdir} ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo static-delta generate --swap-endianness main ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u -repo_init --no-gpg-verify +repo_init --no-sign-verify ${CMD_PREFIX} ostree --repo=repo pull origin main@${prev_rev} ${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas --dry-run origin main >byteswapped-dry-run-pull.txt ${CMD_PREFIX} ostree --repo=repo fsck @@ -451,7 +483,7 @@ echo "ok pull byteswapped delta" cd ${test_tmpdir} rm ostree-srv/gnomerepo/deltas -rf ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u -repo_init --no-gpg-verify +repo_init --no-sign-verify if ${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin main 2>err.txt; then assert_not_reached "--require-static-deltas unexpectedly succeeded" fi @@ -459,7 +491,7 @@ assert_file_has_content err.txt "deltas required, but none found" ${CMD_PREFIX} ostree --repo=repo fsck # Now test with a partial commit -repo_init --no-gpg-verify +repo_init --no-sign-verify ${CMD_PREFIX} ostree --repo=repo pull --commit-metadata-only origin main@${prev_rev} if ${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin main 2>err.txt; then assert_not_reached "--require-static-deltas unexpectedly succeeded" @@ -467,7 +499,7 @@ fi assert_file_has_content err.txt "deltas required, but none found" echo "ok delta required but don't exist" -repo_init --no-gpg-verify +repo_init --no-sign-verify ${CMD_PREFIX} ostree --repo=repo pull origin main@${prev_rev} if ${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin ${new_rev} 2>err.txt; then assert_not_reached "--require-static-deltas unexpectedly succeeded" @@ -595,7 +627,7 @@ if has_gpgme; then fi cd ${test_tmpdir} -repo_init --no-gpg-verify +repo_init --no-sign-verify mv ostree-srv/gnomerepo/refs/heads/main{,.orig} rm ostree-srv/gnomerepo/summary (for x in $(seq 20); do echo "lots of html here "; done) > ostree-srv/gnomerepo/refs/heads/main diff --git a/tests/pull-test2.sh b/tests/pull-test2.sh index 064bbfe6..a0b699ae 100644 --- a/tests/pull-test2.sh +++ b/tests/pull-test2.sh @@ -29,7 +29,7 @@ function repo_init() { ${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo "$@" } -repo_init --no-gpg-verify +repo_init --no-sign-verify # See also the copy of this in basic-test.sh COMMIT_ARGS="" @@ -48,7 +48,7 @@ fi echo "1..1" cd ${test_tmpdir} -repo_init --no-gpg-verify +repo_init --no-sign-verify prev_rev=$(ostree --repo=ostree-srv/repo rev-parse ${remote_ref}^) rev=$(ostree --repo=ostree-srv/repo rev-parse ${remote_ref}) ${CMD_PREFIX} ostree --repo=ostree-srv/repo static-delta generate ${remote_ref} diff --git a/tests/test-admin-deploy-nomerge.sh b/tests/test-admin-deploy-nomerge.sh new file mode 100755 index 00000000..06271421 --- /dev/null +++ b/tests/test-admin-deploy-nomerge.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# +# Copyright (C) 2020 Red Hat, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime + +echo "1..1" +${CMD_PREFIX} ostree admin deploy --os=testos --karg=root=LABEL=foo --karg=testkarg=1 testos:testos/buildmaster/x86_64-runtime +origdeployment=$(${CMD_PREFIX} ostree admin --sysroot=sysroot --print-current-dir) +testconfig=etc/modified-config-file-that-will-be-removed +touch "${origdeployment}"/"${testconfig}" +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf "^options.*root=LABEL=foo.*testkarg" +${CMD_PREFIX} ostree admin deploy --os=testos --no-merge --karg=root=LABEL=bar testos:testos/buildmaster/x86_64-runtime +deployment=$(${CMD_PREFIX} ostree admin --sysroot=sysroot --print-current-dir) +assert_not_streq "${origdeployment}" "${deployment}" +assert_not_has_file "${deployment}/${testconfig}" +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf "^options root=LABEL=bar" +assert_not_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf "^options .*testkarg" +echo "ok no merge deployment" diff --git a/tests/test-admin-deploy-uboot.sh b/tests/test-admin-deploy-uboot.sh index 8ea37fe9..e3163cb0 100755 --- a/tests/test-admin-deploy-uboot.sh +++ b/tests/test-admin-deploy-uboot.sh @@ -25,9 +25,11 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive" "uboot" +kver="3.6.0" +modulesdir="usr/lib/modules/${kver}" +setup_os_repository "archive" "uboot" ${modulesdir} -extra_admin_tests=1 +extra_admin_tests=2 . $(dirname $0)/admin-test.sh @@ -52,3 +54,27 @@ assert_file_has_content sysroot/boot/uEnv.txt "kernel_image2=" assert_file_has_content sysroot/boot/uEnv.txt "kernel_image3=" echo "ok merging uEnv.txt files" + +cd ${test_tmpdir} +os_repository_new_commit "uboot test" "test with device tree directory" + +devicetree_path=osdata/${modulesdir}/dtb/asoc-board.dtb +devicetree_overlay_path=osdata/${modulesdir}/dtb/overlays/overlay.dtbo + +mkdir -p osdata/${modulesdir}/dtb +echo "a device tree" > ${devicetree_path} +mkdir -p osdata/${modulesdir}/dtb/overlays +echo "a device tree overlay" > ${devicetree_overlay_path} + +bootcsum=$( + (echo "new: a kernel uboot test" && echo "new: an initramfs uboot test" && + cat ${devicetree_path} ${devicetree_overlay_path} ) | + sha256sum | cut -f 1 -d ' ') + +${CMD_PREFIX} ostree --repo=testos-repo commit --tree=dir=osdata/ -b testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin upgrade --os=testos +assert_file_has_content sysroot/boot/uEnv.txt "fdtdir=" +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/dtb/asoc-board.dtb 'a device tree' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/dtb/overlays/overlay.dtbo 'a device tree overlay' + +echo "ok deploying fdtdir" diff --git a/tests/test-archivez.sh b/tests/test-archivez.sh index 0dccd737..c27ce03f 100755 --- a/tests/test-archivez.sh +++ b/tests/test-archivez.sh @@ -23,7 +23,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -echo '1..12' +echo '1..13' setup_test_repository "archive" diff --git a/tests/test-local-pull-depth.sh b/tests/test-local-pull-depth.sh index 7080e121..96b20b9c 100755 --- a/tests/test-local-pull-depth.sh +++ b/tests/test-local-pull-depth.sh @@ -34,21 +34,31 @@ ostree_repo_init repo2 --mode="archive" ${CMD_PREFIX} ostree --repo=repo2 pull-local repo find repo2/objects -name '*.commit' | wc -l > commitcount assert_file_has_content commitcount "^1$" +find repo2/state -name '*.commitpartial' | wc -l > commitpartialcount +assert_file_has_content commitpartialcount "^0$" ${CMD_PREFIX} ostree --repo=repo2 pull-local --depth=0 repo find repo2/objects -name '*.commit' | wc -l > commitcount assert_file_has_content commitcount "^1$" +find repo2/state -name '*.commitpartial' | wc -l > commitpartialcount +assert_file_has_content commitpartialcount "^0$" + +${CMD_PREFIX} ostree --repo=repo2 pull-local --depth=1 --commit-metadata-only repo +find repo2/objects -name '*.commit' | wc -l > commitcount +assert_file_has_content commitcount "^2$" +find repo2/state -name '*.commitpartial' | wc -l > commitpartialcount +assert_file_has_content commitpartialcount "^1$" ${CMD_PREFIX} ostree --repo=repo2 pull-local --depth=1 repo find repo2/objects -name '*.commit' | wc -l > commitcount assert_file_has_content commitcount "^2$" - -${CMD_PREFIX} ostree --repo=repo2 pull-local --depth=1 repo -find repo2/objects -name '*.commit' | wc -l > commitcount -assert_file_has_content commitcount "^2$" +find repo2/state -name '*.commitpartial' | wc -l > commitpartialcount +assert_file_has_content commitpartialcount "^0$" ${CMD_PREFIX} ostree --repo=repo2 pull-local --depth=-1 repo find repo2/objects -name '*.commit' | wc -l > commitcount assert_file_has_content commitcount "^2$" +find repo2/state -name '*.commitpartial' | wc -l > commitpartialcount +assert_file_has_content commitpartialcount "^0$" echo "ok local pull depth" diff --git a/tests/test-local-pull.sh b/tests/test-local-pull.sh index 97bb9954..555e9b26 100755 --- a/tests/test-local-pull.sh +++ b/tests/test-local-pull.sh @@ -28,12 +28,7 @@ unset OSTREE_GPG_HOME skip_without_user_xattrs -if has_gpgme; then - echo "1..8" -else - # Only some tests doesn't need GPG support - echo "1..5" -fi +echo "1..8" setup_test_repository "archive" echo "ok setup" @@ -68,6 +63,49 @@ cmp checkout1.files checkout2.files cmp checkout1.files checkout3.files echo "ok checkouts same" +if has_gpgme; then + # These tests are needed GPG support + mkdir repo4 + ostree_repo_init repo4 --mode="archive" + ${CMD_PREFIX} ostree --repo=repo4 remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc origin repo + + if ${CMD_PREFIX} ostree --repo=repo4 pull-local --remote=origin --gpg-verify repo test2 2>&1; then + assert_not_reached "GPG verification unexpectedly succeeded" + fi + echo "ok --gpg-verify with no signature" + + ${OSTREE} gpg-sign --gpg-homedir=${TEST_GPG_KEYHOME} test2 ${TEST_GPG_KEYID_1} + + mkdir repo5 + ostree_repo_init repo5 --mode="archive" + ${CMD_PREFIX} ostree --repo=repo5 remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc origin repo + ${CMD_PREFIX} ostree --repo=repo5 pull-local --remote=origin --gpg-verify repo test2 + echo "ok --gpg-verify" + + mkdir repo6 + ostree_repo_init repo6 --mode="archive" + ${CMD_PREFIX} ostree --repo=repo6 remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc origin repo + if ${CMD_PREFIX} ostree --repo=repo6 pull-local --remote=origin --gpg-verify-summary repo test2 2>&1; then + assert_not_reached "GPG summary verification with no summary unexpectedly succeeded" + fi + + ${OSTREE} summary --update + + if ${CMD_PREFIX} ostree --repo=repo6 pull-local --remote=origin --gpg-verify-summary repo test2 2>&1; then + assert_not_reached "GPG summary verification with signed no summary unexpectedly succeeded" + fi + + ${OSTREE} summary --update --gpg-sign=${TEST_GPG_KEYID_1} --gpg-homedir=${TEST_GPG_KEYHOME} + + ${CMD_PREFIX} ostree --repo=repo6 pull-local --remote=origin --gpg-verify-summary repo test2 2>&1 + + echo "ok --gpg-verify-summary" +else + echo "ok --gpg-verify with no signature | # SKIP due GPG unavailability" + echo "ok --gpg-verify | # SKIP due GPG unavailability" + echo "ok --gpg-verify-summary | # SKIP due GPG unavailability" +fi + mkdir repo7 ostree_repo_init repo7 --mode="archive" ${CMD_PREFIX} ostree --repo=repo7 pull-local repo @@ -77,42 +115,3 @@ for src_object in `find repo/objects -name '*.filez'`; do assert_files_hardlinked "$src_object" "$dst_object" done echo "ok pull-local z2 to z2 default hardlink" - -if ! has_gpgme; then - exit 0 -fi - -mkdir repo4 -ostree_repo_init repo4 --mode="archive" -${CMD_PREFIX} ostree --repo=repo4 remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc origin repo -if ${CMD_PREFIX} ostree --repo=repo4 pull-local --remote=origin --gpg-verify repo test2 2>&1; then - assert_not_reached "GPG verification unexpectedly succeeded" -fi -echo "ok --gpg-verify with no signature" - -${OSTREE} gpg-sign --gpg-homedir=${TEST_GPG_KEYHOME} test2 ${TEST_GPG_KEYID_1} - -mkdir repo5 -ostree_repo_init repo5 --mode="archive" -${CMD_PREFIX} ostree --repo=repo5 remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc origin repo -${CMD_PREFIX} ostree --repo=repo5 pull-local --remote=origin --gpg-verify repo test2 -echo "ok --gpg-verify" - -mkdir repo6 -ostree_repo_init repo6 --mode="archive" -${CMD_PREFIX} ostree --repo=repo6 remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc origin repo -if ${CMD_PREFIX} ostree --repo=repo6 pull-local --remote=origin --gpg-verify-summary repo test2 2>&1; then - assert_not_reached "GPG summary verification with no summary unexpectedly succeeded" -fi - -${OSTREE} summary --update - -if ${CMD_PREFIX} ostree --repo=repo6 pull-local --remote=origin --gpg-verify-summary repo test2 2>&1; then - assert_not_reached "GPG summary verification with signed no summary unexpectedly succeeded" -fi - -${OSTREE} summary --update --gpg-sign=${TEST_GPG_KEYID_1} --gpg-homedir=${TEST_GPG_KEYHOME} - -${CMD_PREFIX} ostree --repo=repo6 pull-local --remote=origin --gpg-verify-summary repo test2 2>&1 - -echo "ok --gpg-verify-summary" diff --git a/tests/test-pre-signed-pull.sh b/tests/test-pre-signed-pull.sh new file mode 100755 index 00000000..20f2b597 --- /dev/null +++ b/tests/test-pre-signed-pull.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# +# Copyright (C) 2020 Collabora Ltd. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..1" + +if ! has_sign_ed25519; then + echo "ok pre-signed pull # SKIP due ed25519 unavailability" + exit 0 +fi + +mkdir upstream +cd upstream +tar xzf $(dirname $0)/pre-signed-pull-data.tar.gz +cd .. + +pubkey='45yzbkuEok0lLabxzdAHWUDSMZgYfxU40sN+LMfYHVA=' + +ostree --repo=repo init --mode=archive +ostree --repo=repo remote add upstream --set=gpg-verify=false --sign-verify=ed25519=inline:${pubkey} file://$(pwd)/upstream/repo +ostree --repo=repo pull upstream:testref + +wrongkey=$(gen_ed25519_random_public) +rm repo -rf +ostree --repo=repo init --mode=archive +ostree --repo=repo remote add badupstream --set=gpg-verify=false --sign-verify=ed25519=inline:${wrongkey} file://$(pwd)/upstream/repo +if ostree --repo=repo pull badupstream:testref 2>err.txt; then + fatal "pulled with wrong key" +fi +assert_file_has_content err.txt 'error:.* ed25519: Signature couldn.t be verified with: key' +echo "ok pre-signed pull" diff --git a/tests/test-pull-collections.sh b/tests/test-pull-collections.sh index d1de5f88..cd60ab21 100755 --- a/tests/test-pull-collections.sh +++ b/tests/test-pull-collections.sh @@ -23,7 +23,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -echo '1..6' +echo '1..7' cd ${test_tmpdir} @@ -258,3 +258,15 @@ then fi echo "ok 6 pull refs from local repos" + +ostree_repo_init local-mirror +do_remote_add local-mirror collection-repo --collection-id org.example.CollectionRepo +# Generate a summary in the local mirror; don't use do_summary to avoid gpg +${CMD_PREFIX} ostree --repo=local-mirror summary --update +summarysig=$(sha256sum < local-mirror/summary | cut -f 1 -d ' ') +# Mirror subset of refs: A collection-ref version of https://github.com/ostreedev/ostree/issues/846 +${CMD_PREFIX} ostree --repo=local-mirror find-remotes --pull --mirror --finders=config org.example.CollectionRepo goodcref1 +newsummarysig=$(sha256sum < local-mirror/summary | cut -f 1 -d ' ') +assert_streq ${summarysig} ${newsummarysig} + +echo "ok 7 mirror pull subset of collection-refs with summary" diff --git a/tests/test-pull-mirrorlist.sh b/tests/test-pull-mirrorlist.sh index 85ff66e9..ed65eb64 100755 --- a/tests/test-pull-mirrorlist.sh +++ b/tests/test-pull-mirrorlist.sh @@ -75,7 +75,7 @@ EOF cd ${test_tmpdir} mkdir repo ostree_repo_init repo -${CMD_PREFIX} ostree --repo=repo remote add origin --no-gpg-verify \ +${CMD_PREFIX} ostree --repo=repo remote add origin --no-sign-verify \ mirrorlist=$(cat httpd-address)/ostree/mirrorlist ${CMD_PREFIX} ostree --repo=repo pull origin:main @@ -87,7 +87,7 @@ cd ${test_tmpdir} rm -rf repo mkdir repo ostree_repo_init repo -${CMD_PREFIX} ostree --repo=repo remote add origin --no-gpg-verify \ +${CMD_PREFIX} ostree --repo=repo remote add origin --no-sign-verify \ --contenturl=mirrorlist=$(cat httpd-address)/ostree/mirrorlist \ $(cat httpd-address)/ostree/gnomerepo ${CMD_PREFIX} ostree --repo=repo pull origin:main @@ -100,7 +100,7 @@ cd ${test_tmpdir} rm -rf repo mkdir repo ostree_repo_init repo -${CMD_PREFIX} ostree --repo=repo remote add origin --no-gpg-verify \ +${CMD_PREFIX} ostree --repo=repo remote add origin --no-sign-verify \ --contenturl=mirrorlist=$(cat httpd-address)/ostree/mirrorlist \ mirrorlist=$(cat httpd-address)/ostree/mirrorlist ${CMD_PREFIX} ostree --repo=repo pull origin:main diff --git a/tests/test-pull-repeated.sh b/tests/test-pull-repeated.sh index 237a863c..f0ea157e 100755 --- a/tests/test-pull-repeated.sh +++ b/tests/test-pull-repeated.sh @@ -92,8 +92,8 @@ pushd ${test_tmpdir} ostree_repo_init repo --mode=archive ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo -# Using 8 network retries gives error rate of <0.5%, when --random-408s=50 -${CMD_PREFIX} ostree --repo=repo pull --mirror origin --network-retries=8 main +# We limit 408s above to 100, so 100 retries should be enough always. +${CMD_PREFIX} ostree --repo=repo pull --mirror origin --network-retries=100 main echo "Success with big number of network retries" ${CMD_PREFIX} ostree --repo=repo fsck diff --git a/tests/test-pull-sizes.sh b/tests/test-pull-sizes.sh index 8ee07cc8..1ce0a736 100755 --- a/tests/test-pull-sizes.sh +++ b/tests/test-pull-sizes.sh @@ -23,6 +23,8 @@ set -euo pipefail . $(dirname $0)/libtest.sh +# Committing SELinux attributes throws off the hardcoded sizes below +export OSTREE_NO_XATTRS=1 setup_fake_remote_repo1 "archive" "--generate-sizes" echo '1..3' diff --git a/tests/test-refs-collections.sh b/tests/test-refs-collections.sh index bf233970..d33f498c 100755 --- a/tests/test-refs-collections.sh +++ b/tests/test-refs-collections.sh @@ -112,7 +112,7 @@ mkdir collection-repo ostree_repo_init collection-repo --collection-id org.example.RemoteCollection mkdir -p adir ${CMD_PREFIX} ostree --repo=collection-repo commit --branch=rcommit -m rcommit -s rcommit adir -${CMD_PREFIX} ostree --repo=repo remote add --no-gpg-verify --collection-id org.example.RemoteCollection collection-repo-remote "file://${test_tmpdir}/collection-repo" +${CMD_PREFIX} ostree --repo=repo remote add --no-sign-verify --collection-id org.example.RemoteCollection collection-repo-remote "file://${test_tmpdir}/collection-repo" ${CMD_PREFIX} ostree --repo=repo pull collection-repo-remote rcommit ${CMD_PREFIX} ostree --repo=repo refs --collections > refs @@ -129,7 +129,7 @@ mkdir no-collection-repo ostree_repo_init no-collection-repo mkdir -p adir2 ${CMD_PREFIX} ostree --repo=no-collection-repo commit --branch=rcommit2 -m rcommit2 -s rcommit2 adir2 -${CMD_PREFIX} ostree --repo=repo remote add --no-gpg-verify no-collection-repo-remote "file://${test_tmpdir}/no-collection-repo" +${CMD_PREFIX} ostree --repo=repo remote add --no-sign-verify no-collection-repo-remote "file://${test_tmpdir}/no-collection-repo" ${CMD_PREFIX} ostree --repo=repo pull no-collection-repo-remote rcommit2 ${CMD_PREFIX} ostree --repo=repo refs --collections > refs assert_not_file_has_content refs "rcommit2" diff --git a/tests/test-remote-add.sh b/tests/test-remote-add.sh index bb7eae89..40a32f57 100755 --- a/tests/test-remote-add.sh +++ b/tests/test-remote-add.sh @@ -30,20 +30,20 @@ $OSTREE remote add origin http://example.com/ostree/gnome $OSTREE remote show-url origin >/dev/null echo "ok config" -$OSTREE remote add --no-gpg-verify another http://another.com/repo +$OSTREE remote add --no-sign-verify another http://another.com/repo $OSTREE remote show-url another >/dev/null echo "ok remote no gpg-verify" -if $OSTREE remote add --no-gpg-verify another http://another.example.com/anotherrepo 2>err.txt; then +if $OSTREE remote add --no-sign-verify another http://another.example.com/anotherrepo 2>err.txt; then assert_not_reached "Adding duplicate remote unexpectedly succeeded" fi echo "ok" -$OSTREE remote add --if-not-exists --no-gpg-verify another http://another.example.com/anotherrepo +$OSTREE remote add --if-not-exists --no-sign-verify another http://another.example.com/anotherrepo $OSTREE remote show-url another >/dev/null echo "ok" -$OSTREE remote add --if-not-exists --no-gpg-verify another-noexist http://another-noexist.example.com/anotherrepo +$OSTREE remote add --if-not-exists --no-sign-verify another-noexist http://another-noexist.example.com/anotherrepo $OSTREE remote show-url another-noexist >/dev/null echo "ok" @@ -69,7 +69,7 @@ cd ${test_tmpdir} rm -rf parent-repo ostree_repo_init parent-repo $OSTREE config set core.parent ${test_tmpdir}/parent-repo -${CMD_PREFIX} ostree --repo=parent-repo remote add --no-gpg-verify parent-remote http://parent-remote.example.com/parent-remote +${CMD_PREFIX} ostree --repo=parent-repo remote add --no-sign-verify parent-remote http://parent-remote.example.com/parent-remote $OSTREE remote list > list.txt assert_file_has_content list.txt "origin" assert_file_has_content list.txt "another" diff --git a/tests/test-remotes-config-dir.js b/tests/test-remotes-config-dir.js index 5588116b..f73a82ef 100755 --- a/tests/test-remotes-config-dir.js +++ b/tests/test-remotes-config-dir.js @@ -94,16 +94,22 @@ print("ok add-in-remotes-config-dir"); // Trying to set a remote config option via write_config() for a remote // defined in the config file should succeed -let [, gpg_verify] = repo.remote_get_gpg_verify('bar'); -assertEquals(gpg_verify, true); -repoConfig = repo.copy_config(); -repoConfig.set_boolean('remote "bar"', 'gpg-verify', false); -repo.write_config(repoConfig); -repo.reload_config(null); -[, gpg_verify] = repo.remote_get_gpg_verify('bar'); -assertEquals(gpg_verify, false); - -print("ok config-remote-in-config-file-succeeds"); +try { + let [, gpg_verify] = repo.remote_get_gpg_verify('bar'); + assertEquals(gpg_verify, true); + repoConfig = repo.copy_config(); + repoConfig.set_boolean('remote "bar"', 'gpg-verify', false); + repo.write_config(repoConfig); + repo.reload_config(null); + [, gpg_verify] = repo.remote_get_gpg_verify('bar'); + assertEquals(gpg_verify, false); + print("ok config-remote-in-config-file-succeeds"); +} catch (e) { + // Skip this test if GPG is not supported + if (!(e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_SUPPORTED))) + throw e; + print("ok config-remote-in-config-file-succeeds # SKIP due build without GPG support"); +} // Trying to set a remote config option via write_config() for a remote // defined in the config dir should fail with G_IO_ERROR_EXISTS diff --git a/tests/test-signed-commit.sh b/tests/test-signed-commit.sh new file mode 100755 index 00000000..d43efef7 --- /dev/null +++ b/tests/test-signed-commit.sh @@ -0,0 +1,208 @@ +#!/bin/bash +# +# Copyright (C) 2019 Collabora Ltd. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..11" + +# This is explicitly opt in for testing +export OSTREE_DUMMY_SIGN_ENABLED=1 + +mkdir ${test_tmpdir}/repo +ostree_repo_init repo --mode="archive" + +echo "Unsigned commit" > file.txt +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s 'Unsigned commit' +COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)" + +# Test `ostree sign` with dummy module first +DUMMYSIGN="dummysign" +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy ${COMMIT} ${DUMMYSIGN} + +# Ensure that detached metadata really contain expected string +EXPECTEDSIGN="$(echo $DUMMYSIGN | hexdump -n 9 -e '8/1 "0x%.2x, " 1/1 " 0x%.2x"')" +${CMD_PREFIX} ostree --repo=repo show ${COMMIT} --print-detached-metadata-key=ostree.sign.dummy | grep -q -e "${EXPECTEDSIGN}" +echo "ok Detached dummy signature added" + +# Verify vith sign mechanism +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy --verify ${COMMIT} ${DUMMYSIGN} +echo "ok dummy signature verified" + +echo "Signed commit with dummy key: ${DUMMYSIGN}" >> file.txt +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s 'Signed with dummy module' --sign=${DUMMYSIGN} --sign-type=dummy +COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)" +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy --verify ${COMMIT} ${DUMMYSIGN} +echo "ok commit with dummy signing" + +if ${CMD_PREFIX} env -u OSTREE_DUMMY_SIGN_ENABLED ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy --verify ${COMMIT} ${DUMMYSIGN} 2>err.txt; then + fatal "verified dummy signature without env" +fi +# FIXME the error message here is broken +#assert_file_has_content_literal err.txt 'dummy signature type is only for ostree testing' +assert_file_has_content_literal err.txt ' No valid signatures found' +echo "ok dummy sig requires env" + +# tests below require libsodium support +if ! has_sign_ed25519; then + echo "ok Detached ed25519 signature # SKIP due libsodium unavailability" + echo "ok ed25519 signature verified # SKIP due libsodium unavailability" + echo "ok multiple signing # SKIP due libsodium unavailability" + echo "ok verify ed25519 keys file # SKIP due libsodium unavailability" + echo "ok sign with ed25519 keys file # SKIP due libsodium unavailability" + echo "ok verify ed25519 system-wide configuration # SKIP due libsodium unavailability" + echo "ok verify ed25519 revoking keys mechanism # SKIP due libsodium unavailability" + exit 0 +fi + +# Test ostree sign with 'ed25519' module +gen_ed25519_keys +PUBLIC=${ED25519PUBLIC} +SEED=${ED25519SEED} +SECRET=${ED25519SECRET} + +WRONG_PUBLIC="$(gen_ed25519_random_public)" + +echo "SEED = $SEED" +echo "PUBLIC = $PUBLIC" + +echo "Signed commit with ed25519: ${SECRET}" >> file.txt +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s "Signed with ed25519 module" --sign="${SECRET}" --sign-type=ed25519 +COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)" + +# Ensure that detached metadata contain signature +${CMD_PREFIX} ostree --repo=repo show ${COMMIT} --print-detached-metadata-key=ostree.sign.ed25519 &>/dev/null +echo "ok Detached ed25519 signature added" + +# Verify vith sign mechanism +if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} ${WRONG_PUBLIC}; then + exit 1 +fi +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} ${PUBLIC} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} ${PUBLIC} ${PUBLIC} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} $(gen_ed25519_random_public) ${PUBLIC} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} $(gen_ed25519_random_public) $(gen_ed25519_random_public) ${PUBLIC} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} ${PUBLIC} $(gen_ed25519_random_public) $(gen_ed25519_random_public) +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} $(gen_ed25519_random_public) $(gen_ed25519_random_public) ${PUBLIC} $(gen_ed25519_random_public) $(gen_ed25519_random_public) +echo "ok ed25519 signature verified" + +# Check if we able to use all available modules to sign the same commit +echo "Unsigned commit for multi-sign" >> file.txt +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s 'Unsigned commit' +COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)" +# Check if we have no signatures +for mod in "dummy" "ed25519"; do + if ostree --repo=repo show ${COMMIT} --print-detached-metadata-key=ostree.sign.${mod}; then + echo "Unexpected signature for ${mod} found" + exit 1 + fi +done + +# Sign with all available modules +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy ${COMMIT} ${DUMMYSIGN} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=ed25519 ${COMMIT} ${SECRET} +# and verify +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} ${PUBLIC} >out.txt +assert_file_has_content out.txt "ed25519: Signature verified successfully with key" +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy --verify ${COMMIT} ${DUMMYSIGN} >out.txt +assert_file_has_content out.txt "dummy: Signature verified" +echo "ok multiple signing " + +# Prepare files with public ed25519 signatures +PUBKEYS="$(mktemp -p ${test_tmpdir} ed25519_XXXXXX.ed25519)" + +# Test if file contain no keys +if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${PUBKEYS} ${COMMIT}; then + exit 1 +fi + +# Test if have a problem with file object +if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${test_tmpdir} ${COMMIT}; then + exit 1 +fi + +# Test with single key in list +echo ${PUBLIC} > ${PUBKEYS} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${PUBKEYS} ${COMMIT} >out.txt +assert_file_has_content out.txt 'ed25519: Signature verified successfully' + +# Test the file with multiple keys without a valid public key +for((i=0;i<100;i++)); do + # Generate a list with some public signatures + gen_ed25519_random_public +done > ${PUBKEYS} +# Check if file contain no valid signatures +if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${PUBKEYS} ${COMMIT} 2>err.txt; then + fatal "validated with no signatures" +fi +assert_file_has_content err.txt 'error:.* ed25519: Signature couldn.t be verified; tried 100 keys' +# Check if no valid signatures provided via args&file +if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${PUBKEYS} ${COMMIT} ${WRONG_PUBLIC}; then + exit 1 +fi + +#Test keys file and public key +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${PUBKEYS} ${COMMIT} ${PUBLIC} + +# Add correct key into the list +echo ${PUBLIC} >> ${PUBKEYS} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${PUBKEYS} ${COMMIT} + +echo "ok verify ed25519 keys file" + +# Check ed25519 signing with secret file +echo "Unsigned commit for secret file usage" >> file.txt +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s 'Unsigned commit' +COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)" + +KEYFILE="$(mktemp -p ${test_tmpdir} secret_XXXXXX.ed25519)" +echo "${SECRET}" > ${KEYFILE} +# Sign +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=ed25519 --keys-file=${KEYFILE} ${COMMIT} +# Verify +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${PUBKEYS} ${COMMIT} +echo "ok sign with ed25519 keys file" + +# Check the well-known places mechanism +mkdir -p ${test_tmpdir}/{trusted,revoked}.ed25519.d +for((i=0;i<100;i++)); do + # Generate some key files with random public signatures + gen_ed25519_random_public > ${test_tmpdir}/trusted.ed25519.d/signature_$i +done +# Check no valid public keys are available +if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-dir=${test_tmpdir} ${COMMIT}; then + exit 1 +fi +echo ${PUBLIC} > ${test_tmpdir}/trusted.ed25519.d/correct +# Verify with correct key +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-dir=${test_tmpdir} ${COMMIT} + +echo "ok verify ed25519 system-wide configuration" + +# Add the public key into revoked list +echo ${PUBLIC} > ${test_tmpdir}/revoked.ed25519.d/correct +# Check if public key is not valid anymore +if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-dir=${test_tmpdir} ${COMMIT}; then + exit 1 +fi +rm -rf ${test_tmpdir}/{trusted,revoked}.ed25519.d +echo "ok verify ed25519 revoking keys mechanism" diff --git a/tests/test-signed-pull-summary.sh b/tests/test-signed-pull-summary.sh new file mode 100755 index 00000000..e953f2ea --- /dev/null +++ b/tests/test-signed-pull-summary.sh @@ -0,0 +1,290 @@ +#!/bin/bash +# +# Copyright (C) 2019 Collabora Ltd. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# Based on test-pull-summary-sigs.sh test. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..14" + +# This is explicitly opt in for testing +export OSTREE_DUMMY_SIGN_ENABLED=1 + +repo_reinit () { + ARGS="$*" + cd ${test_tmpdir} + rm -rf repo + mkdir repo + ostree_repo_init repo --mode=archive + ${OSTREE} --repo=repo remote add \ + --set=gpg-verify=false --set=gpg-verify-summary=false \ + --set=sign-verify=false --set=sign-verify-summary=true \ + ${ARGS} origin $(cat httpd-address)/ostree/gnomerepo +} + +for engine in dummy ed25519 +do + case "${engine}" in + dummy) + # Tests with dummy engine + SIGN_KEY="dummysign" + PUBLIC_KEY="dummysign" + ;; + ed25519) + if ! has_sign_ed25519; then + echo "ok ${engine} pull mirror summary # SKIP due libsodium unavailability" + echo "ok ${engine} pull with signed summary # SKIP due libsodium unavailability" + echo "ok ${engine} prune summary cache # SKIP due libsodium unavailability" + echo "ok ${engine} pull with signed summary and cachedir # SKIP due libsodium unavailability" + echo "ok ${engine} pull with invalid ${engine} summary signature fails # SKIP due libsodium unavailability" + echo "ok ${engine} pull delta with signed summary # SKIP due libsodium unavailability" + + continue + fi + gen_ed25519_keys + SIGN_KEY="${ED25519SECRET}" + PUBLIC_KEY="${ED25519PUBLIC}" + ;; + *) + fatal "Unsupported engine ${engine}" + ;; + esac + + COMMIT_SIGN="--sign-type=${engine} --sign=${SIGN_KEY}" + + # clenup the testdir prior the next engine + rm -rf ${test_tmpdir}/ostree-srv ${test_tmpdir}/gnomerepo ${test_tmpdir}/httpd ${test_tmpdir}/repo ${test_tmpdir}/cachedir\ + ${test_tmpdir}/main-copy ${test_tmpdir}/other-copy ${test_tmpdir}/yet-another-copy + + setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" + + # Now, setup multiple branches + mkdir ${test_tmpdir}/ostree-srv/other-files + cd ${test_tmpdir}/ostree-srv/other-files + echo 'hello world another object' > hello-world + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_SIGN} -b other -s "A commit" -m "Another Commit body" + + mkdir ${test_tmpdir}/ostree-srv/yet-other-files + cd ${test_tmpdir}/ostree-srv/yet-other-files + echo 'hello world yet another object' > yet-another-hello-world + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_SIGN} -b yet-another -s "A commit" -m "Another Commit body" + + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u + + prev_dir=`pwd` + cd ${test_tmpdir} + ostree_repo_init repo --mode=archive + ${CMD_PREFIX} ostree --repo=repo remote add \ + --set=gpg-verify=false --set=gpg-verify-summary=false \ + --set=sign-verify=false --set=sign-verify-summary=false \ + origin $(cat httpd-address)/ostree/gnomerepo + ${CMD_PREFIX} ostree --repo=repo pull --mirror origin + assert_has_file repo/summary + ${CMD_PREFIX} ostree --repo=repo checkout -U main main-copy + assert_file_has_content main-copy/baz/cow "moo" + ${CMD_PREFIX} ostree --repo=repo checkout -U other other-copy + assert_file_has_content other-copy/hello-world "hello world another object" + ${CMD_PREFIX} ostree --repo=repo checkout -U yet-another yet-another-copy + assert_file_has_content yet-another-copy/yet-another-hello-world "hello world yet another object" + ${CMD_PREFIX} ostree --repo=repo fsck + echo "ok ${engine} pull mirror summary" + + + cd $prev_dir + + ${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} + + cd ${test_tmpdir} + repo_reinit --set=verification-${engine}-key=${PUBLIC_KEY} + ${OSTREE} --repo=repo pull origin main + assert_has_file repo/tmp/cache/summaries/origin + assert_has_file repo/tmp/cache/summaries/origin.sig + + rm repo/tmp/cache/summaries/origin + ${OSTREE} --repo=repo pull origin main + assert_has_file repo/tmp/cache/summaries/origin + + echo "ok ${engine} pull with signed summary" + + touch repo/tmp/cache/summaries/foo + touch repo/tmp/cache/summaries/foo.sig + ${OSTREE} --repo=repo prune + assert_not_has_file repo/tmp/cache/summaries/foo + assert_not_has_file repo/tmp/cache/summaries/foo.sig + assert_has_file repo/tmp/cache/summaries/origin + assert_has_file repo/tmp/cache/summaries/origin.sig + echo "ok ${engine} prune summary cache" + + cd ${test_tmpdir} + repo_reinit --set=verification-${engine}-key=${PUBLIC_KEY} + mkdir cachedir + ${OSTREE} --repo=repo pull --cache-dir=cachedir origin main + assert_not_has_file repo/tmp/cache/summaries/origin + assert_not_has_file repo/tmp/cache/summaries/origin.sig + assert_has_file cachedir/summaries/origin + assert_has_file cachedir/summaries/origin.sig + + rm cachedir/summaries/origin + ${OSTREE} --repo=repo pull --cache-dir=cachedir origin main + assert_not_has_file repo/tmp/cache/summaries/origin + assert_has_file cachedir/summaries/origin + + echo "ok ${engine} pull with signed summary and cachedir" + + cd ${test_tmpdir} + repo_reinit --set=verification-${engine}-key=${PUBLIC_KEY} + mv ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{,.good} + echo invalid > ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig + if ${OSTREE} --repo=repo pull origin main 2>err.txt; then + assert_not_reached "Successful pull with invalid ${engine} signature" + fi + assert_file_has_content err.txt "No signatures found" + mv ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.good,} + echo "ok ${engine} pull with invalid ${engine} summary signature fails" + + # Generate a delta + ${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo static-delta generate --empty main + ${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} + + cd ${test_tmpdir} + repo_reinit --set=verification-${engine}-key=${PUBLIC_KEY} + ${OSTREE} --repo=repo pull origin main + echo "ok ${engine} pull delta with signed summary" + +done + +if ! has_sign_ed25519; then + echo "ok ${engine} pull with signed summary remote old summary # SKIP due libsodium unavailability" + echo "ok ${engine} pull with signed summary broken cache # SKIP due libsodium unavailability" + exit 0 +fi + +gen_ed25519_keys +SIGN_KEY="${ED25519SECRET}" +PUBLIC_KEY="${ED25519PUBLIC}" +COMMIT_SIGN="--sign-type=${engine} --sign=${SIGN_KEY}" + + +# Verify 'ostree remote summary' output. +${OSTREE} --repo=repo remote summary origin > summary.txt +assert_file_has_content summary.txt "* main" +assert_file_has_content summary.txt "* other" +assert_file_has_content summary.txt "* yet-another" +grep static-deltas summary.txt > static-deltas.txt +assert_file_has_content static-deltas.txt \ + $(${OSTREE} --repo=repo rev-parse origin:main) + +## Tests for handling of cached summaries while racing with remote summary updates + +# Make 2 different but valid summary/signature pairs to test races with +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{,.1} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{,.1} +mkdir ${test_tmpdir}/ostree-srv/even-another-files +cd ${test_tmpdir}/ostree-srv/even-another-files +echo 'hello world even another object' > even-another-hello-world +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_SIGN} -b even-another -s "A commit" -m "Another Commit body" +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{,.2} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{,.2} +cd ${test_tmpdir} + +# Reset to the old valid summary and pull to cache it +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.1,} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.1,} +repo_reinit --set=verification-ed25519-key=${PUBLIC_KEY} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Simulate a pull race where the client gets the old summary and the new +# summary signature since it was generated on the server between the +# requests +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.2,} +if ${OSTREE} --repo=repo pull origin main 2>err.txt; then + assert_not_reached "Successful pull with old summary" +fi +assert_file_has_content err.txt "ed25519: Signature couldn't be verified with: key" +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Publish correct summary and check that subsequent pull succeeds +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.2,} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.2 >&2 + +echo "ok ${engine} pull with signed summary remote old summary" + + +# Reset to the old valid summary and pull to cache it +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.1,} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.1,} +repo_reinit --set=verification-ed25519-key=${PUBLIC_KEY} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Simulate a broken summary cache to see if it can be recovered from. +# Prior to commit c4c2b5eb the client would save the summary to the +# cache before validating the signature. That would mean the cache would +# have mismatched summary and signature and ostree would remain +# deadlocked there until the remote published a new signature. +# +# First pull with OSTREE_REPO_TEST_ERROR=invalid-cache to see the +# invalid cache is detected. Then pull again to check if it can be +# recovered from. +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 repo/tmp/cache/summaries/origin +if OSTREE_REPO_TEST_ERROR=invalid-cache ${OSTREE} --repo=repo pull origin main 2>err.txt; then + assert_not_reached "Should have hit OSTREE_REPO_TEST_ERROR_INVALID_CACHE" +fi +assert_file_has_content err.txt "OSTREE_REPO_TEST_ERROR_INVALID_CACHE" +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Publish new signature and check that subsequent pull succeeds +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.2,} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.2,} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.2 >&2 + +echo "ok ${engine} pull with signed summary broken cache" + diff --git a/tests/test-signed-pull.sh b/tests/test-signed-pull.sh new file mode 100755 index 00000000..fe78321a --- /dev/null +++ b/tests/test-signed-pull.sh @@ -0,0 +1,190 @@ +#!/bin/bash +# +# Copyright (C) 2019 Collabora Ltd. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..20" + +# This is explicitly opt in for testing +export OSTREE_DUMMY_SIGN_ENABLED=1 +setup_fake_remote_repo1 "archive" + +repo_mode="archive" + +function repo_init() { + cd ${test_tmpdir} + rm repo -rf + mkdir repo + ostree_repo_init repo --mode=${repo_mode} + ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false --set=sign-verify-summary=false origin $(cat httpd-address)/ostree/gnomerepo "$@" +} + +function test_signed_pull() { + local sign_type="$1" + local comment="$2" + cd ${test_tmpdir} + ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit ${COMMIT_ARGS} \ + -b main -s "A signed commit" --tree=ref=main + + ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u + # make sure gpg verification is correctly on + csum=$(${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo rev-parse main) + objpath=objects/${csum::2}/${csum:2}.commitmeta + remotesig=ostree-srv/gnomerepo/$objpath + localsig=repo/$objpath + mv $remotesig $remotesig.bak + if ${CMD_PREFIX} ostree --repo=repo --depth=0 pull origin main; then + assert_not_reached "pull with sign-verify and no commitmeta unexpectedly succeeded?" + fi + # ok now check that we can pull correctly + mv $remotesig.bak $remotesig + ${CMD_PREFIX} ostree --repo=repo pull origin main + echo "ok ${sign_type}${comment} pull signed commit" + rm $localsig + ${CMD_PREFIX} ostree --repo=repo pull origin main + test -f $localsig + echo "ok ${sign_type}${comment} re-pull signature for stored commit" +} + +DUMMYSIGN="dummysign" +COMMIT_ARGS="--sign=${DUMMYSIGN} --sign-type=dummy" +repo_init --set=sign-verify=true + +# Check if verification-key and verification-file options throw error with wrong keys +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit ${COMMIT_ARGS} \ + -b main -s "A signed commit" --tree=ref=main +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +if ${CMD_PREFIX} ostree --repo=repo pull origin main; then + assert_not_reached "pull without keys unexpectedly succeeded" +fi +echo "ok pull failure without keys preloaded" + +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-dummy-key "somewrongkey" +if ${CMD_PREFIX} ostree --repo=repo pull origin main; then + assert_not_reached "pull with unknown key unexpectedly succeeded" +fi +echo "ok pull failure with incorrect key option" + +${CMD_PREFIX} ostree --repo=repo config unset 'remote "origin"'.verification-dummy-key +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-dummy-file "/non/existing/file" +if ${CMD_PREFIX} ostree --repo=repo pull origin main; then + assert_not_reached "pull with unknown keys file unexpectedly succeeded" +fi +echo "ok pull failure with incorrect keys file option" + +# Test with correct dummy key +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-dummy-key "${DUMMYSIGN}" +${CMD_PREFIX} ostree --repo=repo config unset 'remote "origin"'.verification-dummy-file +test_signed_pull "dummy" "" + +# Another test with the --verify option directly +repo_init --sign-verify=dummy=inline:${DUMMYSIGN} +test_signed_pull "dummy" "from remote opt" + +# And now explicitly limit it to dummy +repo_init +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.sign-verify dummy +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-dummy-key "${DUMMYSIGN}" +test_signed_pull "dummy" "explicit value" + +# dummy, but no key configured +repo_init +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.sign-verify dummy +if ${CMD_PREFIX} ostree --repo=repo pull origin main 2>err.txt; then + assert_not_reached "pull with nosuchsystem succeeded" +fi +assert_file_has_content err.txt 'No keys found for required signapi type dummy' +echo "ok explicit dummy but unconfigured" + +# Set it to an unknown explicit value +repo_init +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.sign-verify nosuchsystem; +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-dummy-key "${DUMMYSIGN}" +if ${CMD_PREFIX} ostree --repo=repo pull origin main 2>err.txt; then + assert_not_reached "pull with nosuchsystem succeeded" +fi +assert_file_has_content err.txt 'Requested signature type is not implemented' +echo "ok pull failure for unknown system" + +repo_init +if ${CMD_PREFIX} ostree --repo=repo remote add other --sign-verify=trustme=inline:ok http://localhost 2>err.txt; then + assert_not_reached "remote add with invalid keytype succeeded" +fi +assert_file_has_content err.txt 'Requested signature type is not implemented' +if ${CMD_PREFIX} ostree --repo=repo remote add other --sign-verify=dummy http://localhost 2>err.txt; then + assert_not_reached "remote add with invalid keytype succeeded" +fi +assert_file_has_content err.txt 'Failed to parse KEYTYPE' +if ${CMD_PREFIX} ostree --repo=repo remote add other --sign-verify=dummy=foo:bar http://localhost 2>err.txt; then + assert_not_reached "remote add with invalid keytype succeeded" +fi +assert_file_has_content err.txt 'Invalid key reference' +echo "ok remote add errs" + +if ! has_sign_ed25519; then + echo "ok ed25519-key pull signed commit # SKIP due libsodium unavailability" + echo "ok ed25519-key re-pull signature for stored commit # SKIP due libsodium unavailability" + echo "ok ed25519-key+file pull signed commit # SKIP due libsodium unavailability" + echo "ok ed25519-key+file re-pull signature for stored commit # SKIP due libsodium unavailability" + echo "ok ed25519-file pull signed commit # SKIP due libsodium unavailability" + echo "ok ed25519-file re-pull signature for stored commit # SKIP due libsodium unavailability" + echo "ok ed25519-inline # SKIP due libsodium unavailability" + echo "ok ed25519-inline # SKIP due libsodium unavailability" + exit 0 +fi + +# Test ostree sign with 'ed25519' module +gen_ed25519_keys +PUBLIC=${ED25519PUBLIC} +SEED=${ED25519SEED} +SECRET=${ED25519SECRET} + +COMMIT_ARGS="--sign=${SECRET} --sign-type=ed25519" + +repo_init --set=sign-verify=true +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-ed25519-key "${PUBLIC}" +test_signed_pull "ed25519" "key" + +# Prepare files with public ed25519 signatures +PUBKEYS="$(mktemp -p ${test_tmpdir} ed25519_XXXXXX.ed25519)" + +# Test the file with multiple keys without a valid public key +for((i=0;i<100;i++)); do + # Generate a list with some public signatures + gen_ed25519_random_public +done > ${PUBKEYS} + +# Test case with the file containing incorrect signatures and with the correct key set +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-ed25519-file "${PUBKEYS}" +test_signed_pull "ed25519" "key+file" + +# Add correct key into the list +echo ${PUBLIC} >> ${PUBKEYS} + +repo_init --set=sign-verify=true +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-ed25519-file "${PUBKEYS}" +test_signed_pull "ed25519" "file" + +repo_init --sign-verify=ed25519=inline:"${ED25519PUBLIC}" +test_signed_pull "ed25519" "--verify-ed25519" diff --git a/tests/test-summary-collections.sh b/tests/test-summary-collections.sh index 777d3d0c..9885c5ea 100755 --- a/tests/test-summary-collections.sh +++ b/tests/test-summary-collections.sh @@ -63,7 +63,7 @@ mkdir collection-repo ostree_repo_init collection-repo --collection-id org.example.RemoteCollection mkdir -p adir ${CMD_PREFIX} ostree --repo=collection-repo commit --branch=rcommit -m rcommit -s rcommit adir -${CMD_PREFIX} ostree --repo=repo remote add --no-gpg-verify --collection-id org.example.RemoteCollection collection-repo-remote "file://${test_tmpdir}/collection-repo" +${CMD_PREFIX} ostree --repo=repo remote add --no-sign-verify --collection-id org.example.RemoteCollection collection-repo-remote "file://${test_tmpdir}/collection-repo" ${CMD_PREFIX} ostree --repo=repo pull collection-repo-remote rcommit ${CMD_PREFIX} ostree --repo=repo summary --update @@ -75,7 +75,7 @@ mkdir no-collection-repo ostree_repo_init no-collection-repo mkdir -p adir2 ${CMD_PREFIX} ostree --repo=no-collection-repo commit --branch=rcommit2 -m rcommit2 -s rcommit2 adir2 -${CMD_PREFIX} ostree --repo=repo remote add --no-gpg-verify no-collection-repo-remote "file://${test_tmpdir}/no-collection-repo" +${CMD_PREFIX} ostree --repo=repo remote add --no-sign-verify no-collection-repo-remote "file://${test_tmpdir}/no-collection-repo" ${CMD_PREFIX} ostree --repo=repo pull no-collection-repo-remote rcommit2 ${CMD_PREFIX} ostree --repo=repo summary --update diff --git a/tests/test-symbols.sh b/tests/test-symbols.sh index f6742d93..75df37e1 100755 --- a/tests/test-symbols.sh +++ b/tests/test-symbols.sh @@ -21,6 +21,8 @@ set -xeuo pipefail +. $(dirname $0)/libtest.sh + echo '1..3' released_syms=${G_TEST_SRCDIR}/src/libostree/libostree-released.sym @@ -41,6 +43,16 @@ echo "Verifying all expected symbols are actually exported..." grep --no-filename ' ostree_[A-Za-z0-9_]*;' ${released_syms} ${devel_syms} ${experimental_sym} | sed -e 's,^ *\([A-Za-z0-9_]*\);,\1,' | sort -u > expected-symbols.txt eu-readelf -a ${G_TEST_BUILDDIR}/.libs/libostree-1.so | grep 'FUNC.*GLOBAL.*DEFAULT.*@@LIBOSTREE_' | sed -e 's,^.* \(ostree_[A-Za-z0-9_]*\)@@LIBOSTREE_[0-9A-Z_.]*,\1,' |sort -u > found-symbols.txt diff -u expected-symbols.txt found-symbols.txt + +echo "Checking that the example symbol wasn't copy-pasted..." +if test -f ${devel_syms}; then + assert_file_has_content_once ${devel_syms} "someostree_symbol_deleteme" +fi +if test -f ${experimental_sym}; then + assert_not_file_has_content ${experimental_sym} "someostree_symbol_deleteme" +fi +assert_not_file_has_content ${released_syms} "someostree_symbol_deleteme" + echo "ok exports" # cmd__private__ is private. The fetcher symbol should not have been made public. @@ -54,7 +66,7 @@ echo 'ok documented symbols' # ONLY update this checksum in release commits! cat > released-sha256.txt <
    typedef