diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0e506f97a96..1997901f6bb 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -278,7 +278,7 @@ jobs: scripts/artifacts/images/flatcar_production_image*.txt scripts/artifacts/images/flatcar_production_image*.json scripts/artifacts/images/flatcar_production_image_pcr_policy.zip - scripts/artifacts/images/flatcar_production_*_efi_*.fd + scripts/artifacts/images/flatcar_production_*_efi_*.qcow2 scripts/artifacts/images/flatcar_production_qemu.sh - name: Upload developer container @@ -317,7 +317,7 @@ jobs: path: | scripts/artifacts/images/*.img scripts/artifacts/images/*.bin - scripts/artifacts/images/flatcar_production_*_efi_*.fd + scripts/artifacts/images/flatcar_production_*_efi_*.qcow2 scripts/artifacts/images/*.txt scripts/artifacts/images/flatcar-*.raw scripts/artifacts/images/flatcar_production_*.sh diff --git a/.github/workflows/portage-stable-packages-list b/.github/workflows/portage-stable-packages-list index 89e859662e7..7e92f85d4a6 100644 --- a/.github/workflows/portage-stable-packages-list +++ b/.github/workflows/portage-stable-packages-list @@ -117,13 +117,13 @@ app-containers/runc app-crypt/adcli app-crypt/argon2 app-crypt/ccid -app-crypt/efitools app-crypt/gnupg app-crypt/gpgme app-crypt/libb2 app-crypt/libmd app-crypt/mhash app-crypt/mit-krb5 +app-crypt/p11-kit app-crypt/pinentry app-crypt/rhash app-crypt/shash @@ -138,6 +138,7 @@ app-editors/vim-core app-emulation/qemu app-emulation/qemu-guest-agent +app-emulation/virt-firmware app-eselect/eselect-iptables app-eselect/eselect-lib-bin-symlink @@ -188,6 +189,10 @@ dev-build/meson-format-array dev-build/ninja dev-cpp/abseil-cpp +dev-cpp/azure-core +dev-cpp/azure-identity +dev-cpp/azure-security-keyvault-certificates +dev-cpp/azure-security-keyvault-keys dev-cpp/gflags dev-cpp/glog dev-cpp/gtest @@ -284,10 +289,12 @@ dev-python/autocommand dev-python/backports-tarfile dev-python/cachecontrol dev-python/certifi +dev-python/cffi dev-python/chardet dev-python/charset-normalizer dev-python/colorama dev-python/crcmod +dev-python/cryptography dev-python/cython dev-python/distlib dev-python/distro @@ -322,11 +329,14 @@ dev-python/olefile dev-python/ordered-set dev-python/packaging dev-python/pathspec +dev-python/pefile dev-python/pillow dev-python/pip dev-python/platformdirs dev-python/pluggy +dev-python/ply dev-python/poetry-core +dev-python/pycparser dev-python/pydecomp dev-python/pygments dev-python/pyproject-hooks @@ -355,6 +365,7 @@ dev-util/desktop-file-utils dev-util/gdbus-codegen dev-util/glib-utils dev-util/gperf +dev-util/maturin dev-util/pahole dev-util/patchelf dev-util/patchutils @@ -450,6 +461,7 @@ eclass/savedconfig.eclass eclass/secureboot.eclass eclass/selinux-policy-2.eclass eclass/sgml-catalog-r1.eclass +eclass/shell-completion.eclass eclass/ssl-cert.eclass eclass/strip-linguas.eclass eclass/subversion.eclass diff --git a/.github/workflows/run-kola-tests.yaml b/.github/workflows/run-kola-tests.yaml index 7e3ea8b039d..a5e7ebf5481 100644 --- a/.github/workflows/run-kola-tests.yaml +++ b/.github/workflows/run-kola-tests.yaml @@ -162,7 +162,7 @@ jobs: # Extract the generic image we'll use for qemu tests. # Note that the qemu[_uefi] tests use the generic image instead of the # qemu vendor VM image ("Astronaut: [...] Always have been."). - mv flatcar_production_image.bin flatcar_production_qemu_uefi_efi_code.fd flatcar_production_qemu_uefi_efi_vars.fd scripts/ + mv flatcar_production_image.bin flatcar_production_qemu_uefi_efi_code.qcow2 flatcar_production_qemu_uefi_efi_vars.qcow2 scripts/ mv flatcar_test_update.gz scripts/ @@ -197,8 +197,8 @@ jobs: cat > sdk_container/.env < sdk_container/.env < + + + + chewi@gentoo.org + James Le Cuirot + + + jepio/azure_keyvault_pkcs11 + + diff --git a/sdk_container/src/third_party/coreos-overlay/app-crypt/p11-kit/Manifest b/sdk_container/src/third_party/coreos-overlay/app-crypt/p11-kit/Manifest deleted file mode 100644 index 8b75e07bb5a..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/app-crypt/p11-kit/Manifest +++ /dev/null @@ -1 +0,0 @@ -DIST p11-kit-0.23.22.tar.xz 830016 BLAKE2B 4e1edfd9e2441d237c07a16c003aee5ffde38f1cf545c26e435645429f2cfa4fe7ca61cdc3c3940390aa040ba991f2ee3995b14cc31bb886d5eeffa8ed5e1721 SHA512 098819e6ca4ad9cc2a0bc2e478aea67354d051a4f03e6c7d75d13d2469b6dc7654f26b15530052f6ed51acb35531c2539e0f971b31e29e6673e857c903afb080 diff --git a/sdk_container/src/third_party/coreos-overlay/app-crypt/p11-kit/README.md b/sdk_container/src/third_party/coreos-overlay/app-crypt/p11-kit/README.md deleted file mode 100644 index 92a30382726..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/app-crypt/p11-kit/README.md +++ /dev/null @@ -1,4 +0,0 @@ -We forked this package to fix the systemd user unit directory and bash -completion directory detection in the cross-compilation scenario. - -These fixes could be upstreamed to gentoo. diff --git a/sdk_container/src/third_party/coreos-overlay/app-crypt/p11-kit/metadata.xml b/sdk_container/src/third_party/coreos-overlay/app-crypt/p11-kit/metadata.xml deleted file mode 100644 index ff17590b69a..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/app-crypt/p11-kit/metadata.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - zlogene@gentoo.org - Mikle Kolyada - - - Enable ASN.1 certificate support - Build the trust policy module - - - p11-glue/p11-kit - - diff --git a/sdk_container/src/third_party/coreos-overlay/app-crypt/p11-kit/p11-kit-0.23.22.ebuild b/sdk_container/src/third_party/coreos-overlay/app-crypt/p11-kit/p11-kit-0.23.22.ebuild deleted file mode 100644 index b36df3db264..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/app-crypt/p11-kit/p11-kit-0.23.22.ebuild +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -# Flatcar: inherit systemd eclass for the systemd user unit directory -# getter, and bash-completion-r1 for bash completion directory getter. -inherit multilib-minimal systemd bash-completion-r1 - -DESCRIPTION="Provides a standard configuration setup for installing PKCS#11" -HOMEPAGE="https://p11-glue.github.io/p11-glue/p11-kit.html" -SRC_URI="https://github.com/p11-glue/p11-kit/releases/download/${PV}/${P}.tar.xz" - -LICENSE="MIT" -SLOT="0" -KEYWORDS="~alpha amd64 arm arm64 hppa ~ia64 ~m68k ~mips ppc ppc64 ~riscv ~s390 sparc x86 ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~sparc-solaris ~sparc64-solaris ~x64-solaris ~x86-solaris" -IUSE="+asn1 debug +libffi systemd +trust" -REQUIRED_USE="trust? ( asn1 )" - -RDEPEND="asn1? ( >=dev-libs/libtasn1-3.4:=[${MULTILIB_USEDEP}] ) - libffi? ( dev-libs/libffi:=[${MULTILIB_USEDEP}] ) - systemd? ( sys-apps/systemd:= ) - trust? ( app-misc/ca-certificates )" -DEPEND="${RDEPEND}" -BDEPEND="virtual/pkgconfig" - -pkg_setup() { - # disable unsafe tests, bug#502088 - export FAKED_MODE=1 -} - -src_prepare() { - if [[ ${CHOST} == *-solaris2.* && ${CHOST##*-solaris2.} -lt 11 ]] ; then - # Solaris 10 and before doesn't know about XPG7 (XOPEN_SOURCE=700) - # drop to XPG6 to make feature_tests.h happy - sed -i -e '/define _XOPEN_SOURCE/s/700/600/' common/compat.c || die - # paths.h isn't available, oddly enough also not used albeit included - sed -i -e '/#include /d' trust/test-trust.c || die - # we don't have SUN_LEN here - sed -i -e 's/SUN_LEN \(([^)]\+)\)/strlen (\1->sun_path)/' \ - p11-kit/server.c || die - fi - default -} - -multilib_src_configure() { - # Flatcar: Override the detection of the systemd user unit - # directory and bash completion directory with these - # environment variables. - local -x systemduserunitdir=$(systemd_get_userunitdir) - local -x bashcompdir=$(get_bashcompdir) - ECONF_SOURCE="${S}" econf \ - $(use_enable trust trust-module) \ - $(use_with trust trust-paths ${EPREFIX}/etc/ssl/certs/ca-certificates.crt) \ - $(use_enable debug) \ - $(use_with libffi) \ - $(use_with asn1 libtasn1) \ - $(multilib_native_use_with systemd) - - if multilib_is_native_abi; then - # re-use provided documentation - ln -s "${S}"/doc/manual/html doc/manual/html || die - fi -} - -multilib_src_install_all() { - einstalldocs - find "${D}" -name '*.la' -delete || die -} diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/README.md b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/README.md index 0231aa542e0..f50820c9450 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/README.md +++ b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/README.md @@ -1,7 +1,5 @@ ## Keys & Certificates -- PK (Platform Key): The Platform Key is the key to the platform. -- KEK (Key Exchange Key): The Key Exchange Key is used to update the signature database. - DB (Signature Database): The signature database is used to validate signed EFI binaries. - Shim Certificates: Our set of certificates diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/coreos-sb-keys-0.0.3.ebuild b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/coreos-sb-keys-1.0.0.ebuild similarity index 78% rename from sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/coreos-sb-keys-0.0.3.ebuild rename to sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/coreos-sb-keys-1.0.0.ebuild index 9562a134a11..5080f9ec8c9 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/coreos-sb-keys-0.0.3.ebuild +++ b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/coreos-sb-keys-1.0.0.ebuild @@ -16,10 +16,6 @@ S="${WORKDIR}" src_install() { insinto /usr/share/sb_keys - newins "${FILESDIR}/PK.key" PK.key - newins "${FILESDIR}/PK.crt" PK.crt - newins "${FILESDIR}/KEK.key" KEK.key - newins "${FILESDIR}/KEK.crt" KEK.crt newins "${FILESDIR}/DB.key" DB.key newins "${FILESDIR}/DB.crt" DB.crt diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/KEK.crt b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/KEK.crt deleted file mode 100644 index 54646e2aae2..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/KEK.crt +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDBzCCAe+gAwIBAgIJAN/ga2oSNhyiMA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNV -BAMMD0NvcmVPUyB0ZXN0IEtFSzAeFw0xNTA0MTMxODMzMzRaFw0xNTA1MTMxODMz -MzRaMBoxGDAWBgNVBAMMD0NvcmVPUyB0ZXN0IEtFSzCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBAL/DE8ss0bgdKgLmyQ6CQsAUpeWwLlxMNca+LROR5+UH -VAa/Xph30xdfmpydWxUO0Ga1ZnyTfZp+UfOWya9kYkzzmmuKAzC0HLzolSWxQ3sL -EDsXEbpfl7KsjDvPuXdVoJukdN8EppqP6DLGjHbY5lk5AfXj7xCP3wHlLzMsPoxu -hkfDfZSB0qJ5r+L6egz50Vufvxn1oiolMWh7zorkQaM5i4cP6BEQtan7WNhKDJAZ -3fbApmcJyOP7TvWLHcAyuI2FM13J89bc7vrclb2PrtAoijNyDnNImLb187/gC8Ab -kHVFIm8KyZ8ZByNoU5hy4bA1U/EEZ+slyIqqKcnWbukCAwEAAaNQME4wHQYDVR0O -BBYEFC1uWlFmCG6L18813V9Xy12dQ/MJMB8GA1UdIwQYMBaAFC1uWlFmCG6L1881 -3V9Xy12dQ/MJMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAEOKN7AS -2szIJ4ejcxRJhih5rBFwVkim80rwBX8Ga3sStAAKEpdZC7fjrxXm8UWYbEa8Qisz -+O74T7QqXaCRoxh3ij4fgg4clULOfjGGWWEghl4rtpUIsarCk3HWtEzqLWbAQOA0 -co3B08KbwYhOYfx1MkRE1K6kFKojJ1tod/w9jxY1/w/qmJKFP/vM6//H9dhVPr14 -4ySqz/NYhb0FZRVGJkeLbXWy4sLZy2Of+ojCRjjAgmY9RAT6ZxovgyXqVBDWfboX -4Yp9bAboktfNtX6+9wMIW5bTuZ5yZjK+I+MnHSqbRVh/6T/kh5j5+jdPXnKgZGXy -PWAnhbRJTjUAVTY= ------END CERTIFICATE----- diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/KEK.key b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/KEK.key deleted file mode 100644 index 0536b49f82b..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/KEK.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC/wxPLLNG4HSoC -5skOgkLAFKXlsC5cTDXGvi0TkeflB1QGv16Yd9MXX5qcnVsVDtBmtWZ8k32aflHz -lsmvZGJM85prigMwtBy86JUlsUN7CxA7FxG6X5eyrIw7z7l3VaCbpHTfBKaaj+gy -xox22OZZOQH14+8Qj98B5S8zLD6MboZHw32UgdKiea/i+noM+dFbn78Z9aIqJTFo -e86K5EGjOYuHD+gRELWp+1jYSgyQGd32wKZnCcjj+071ix3AMriNhTNdyfPW3O76 -3JW9j67QKIozcg5zSJi29fO/4AvAG5B1RSJvCsmfGQcjaFOYcuGwNVPxBGfrJciK -qinJ1m7pAgMBAAECggEAL5jxMc4nJAcBJYU5RIOqo9i8MN3hNAGqm3Ea6S+fGqcO -ATrA9SFQ4Q1W6Cbas8hgjA3cqXFGjPFr0AWOfB1zlNwmaSjxj8Y1F+K3Gor8T+84 -ESKxwMv3cF8J09LEm01Ctz9DzxNtcxHjNa84sEs4Kc9PoEP6U+cSGHtVkuMZh2t9 -hNad8DfdM2oZi5IPcVcBXr/+QmyjereKlTij5BPSdeKw2JKprv0NWgzuZkDlhtAF -aSNLkODk3NT9+zMSqvuSkNkWuvcl8kFG32strHzsEKneugEbLQPLwEA2hRz6gDo2 -alPUo9shg4o54r47pascVJjbiFPevIvF0GTgmv/VAQKBgQDodWPClJZiyifJ6M65 -V4p+N4evhr6xBTxYMTfXoXIT6IwqyiDyhDnjUApM9wwr9YTxixJukAdcdDnWOMJb -qR2JquGXeChPAArH69FzsuybVXURpBiIOBBNFmWf/T97Aw55l6OXxzA/aAuQMFyF -H8zEQddC57yEMIpToTuNkNq8CQKBgQDTLpvNtsqKBxIpnybv2gRo2MDgJtk+PGu/ -UN3f1GDP1C9nhEVWb1n4v7n9bhYs5zra3vYkgvr317QVAbKF+PUmIPLmid5gN8J5 -46+qdVvK88UPJye2cuIrHO/XScWiC95SzQo6KfVNqawLJhioZ3OlK69pOcLoXWsO -/nJC5i6T4QKBgQCM6hx/Z/OCD2nvS+GFGTwrJx5pmRUf2jyqeauQW53704yko8M1 -QFKXKX4VCe2m+D6O7e9OdqD/urUU13N6fRoayivW1lAZE711U860hFJKF5PQDdmR -Oesnz9vrEGna+A9eRj41U9o7labs0WREjvJiRkdnl3L/7yzrZWHkf1sZgQKBgQDJ -X49oKR6XYci68a0yV8WOqOm6lLDhPMJNy3HXBvBOHXoajrGDi2jS3xgehoQUy2V+ -4c763/8qqIBq65RtVgmGEzMsDFmFjIYgrrGKrKAcNjk5is++lWv/SneV5h3TuNeG -Q0i2T94+8UVB2FD4/LT00mRQxaiK5NG6mX0hN9dAYQKBgEC8GarO5+lPEXNhkqcM -rWBtZTszTP9WGs0nB6+ZGZ+23uMwNA/6YZvyvAssfJ9yr4pyI/r2WH0rHa9146s0 -rJx+Xs/TSbGRYDq7BcwjN3DuSvoCg/0arVeoptrmoDIrFOzhlgQWdrIOMqVKTNKi -s/B7OsUuIhJ7HAJSatt2uzam ------END PRIVATE KEY----- diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/PK.crt b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/PK.crt deleted file mode 100644 index 9fcb2a2e17d..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/PK.crt +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDBTCCAe2gAwIBAgIJAPrtEex/4ln3MA0GCSqGSIb3DQEBCwUAMBkxFzAVBgNV -BAMMDkNvcmVPUyB0ZXN0IFBLMB4XDTE1MDQxMzE4MzMyMloXDTE1MDUxMzE4MzMy -MlowGTEXMBUGA1UEAwwOQ29yZU9TIHRlc3QgUEswggEiMA0GCSqGSIb3DQEBAQUA -A4IBDwAwggEKAoIBAQCrAWnfZoNaw4FVFbdkQo+aBTjMnaEs643EdqoXRn8ohmJu -gCnNNy4mcwsxrx7ksSyfU3ZeVeFXFcydAt53F0hFLsWEi/Riw59AImOuyOXxcrK5 -CAzaOqWIs0RvDqvEJjm7JSuOVndeTVFp7d/2up0zJoXltMaZLs3748AyI29aL2jr -PEW8+FZRqp/z9/EWpifcPZXFzqc7QYTwamfznwqUIFXMLqW5bREroFpZ9MMTmc86 -WMQYUySPdCxvQKKgvGyf0qYWVw2mPp6jZZF84dELn1FvNJ4AMIa/d2TGSkNOpPkn -0VTWtmJTZoY2n/0/KHFQPT1Ot7M9/s6pRd8IIfDzAgMBAAGjUDBOMB0GA1UdDgQW -BBRHBFY7ba7b2aOujtUZB1dHVQUqFDAfBgNVHSMEGDAWgBRHBFY7ba7b2aOujtUZ -B1dHVQUqFDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCT3Xs/My5E -ST//7SrupTakH+QRd7/qIFj2/coXuWE0Qp9cWiWIy9GDyd0oyQsKQklVbuLArju4 -N8oekgtJnNoYbJnLs0JPfAIC5Np3wYTNCyjVi8kSyKSWdXM2vKkycG023sFiFdSk -0pgmwCO1E8fGxe9YDjCdtRTp8+j6m5GrRkl3YYfqYtUFfXy+BhcKs1H6AlfaKAZH -m1fYDGmGGuOTij/5yEyY38NJybjL8Aak89nwuVrHm76whldsA3LfPYenjLk5qTd8 -yEYgvoajAZDIXkT05F9E9SdSaob2ZK1nDp98kG+rnv7dN/xQVfaKywuM3cdy5TKk -VqV0ENF7w+O5 ------END CERTIFICATE----- diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/PK.key b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/PK.key deleted file mode 100644 index 589fef190ee..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/PK.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrAWnfZoNaw4FV -FbdkQo+aBTjMnaEs643EdqoXRn8ohmJugCnNNy4mcwsxrx7ksSyfU3ZeVeFXFcyd -At53F0hFLsWEi/Riw59AImOuyOXxcrK5CAzaOqWIs0RvDqvEJjm7JSuOVndeTVFp -7d/2up0zJoXltMaZLs3748AyI29aL2jrPEW8+FZRqp/z9/EWpifcPZXFzqc7QYTw -amfznwqUIFXMLqW5bREroFpZ9MMTmc86WMQYUySPdCxvQKKgvGyf0qYWVw2mPp6j -ZZF84dELn1FvNJ4AMIa/d2TGSkNOpPkn0VTWtmJTZoY2n/0/KHFQPT1Ot7M9/s6p -Rd8IIfDzAgMBAAECggEAZI/0Ptf+LwYBrJOUwXUTFbQ0br/T5KKxP/O4mu9uH9rH -T8w2yOPGU/4beyBMvpgicZ+XYGqIlbnQFhV11frvGSAkL4pOMTZxFDok/MhP0Olu -iLlfNYZ/iiBCAj1SbYs9L/zv3Eik8ePuGKk2p9WeVFI3M5pXoAWSRKruf42vEg0Q -mAvjpabEFi41RavmO6EuDt5m6VOO3wgGXBZw/+skTtCtlhABK08aggV4a1jrrAJX -FVH8+XmYG7xknxMLxQYSuG1H0n86iext1+jtL74qd51PeaVzfXfE00xjnM08naV+ -XivpwhxsSo0aSMsuOipvMefvQDDwbYVN1RVlEIDuoQKBgQDhRy7j2Dz1zN+C0Bg3 -X2xInQGHq3MineGa/DCzN17rGT0jYB/9FMZTSfk60RNzFacHgLhfSxk0sPfBdi+J -WGWjm48nVz/vsx6V8DNOYiHoi2DxdpHoohUzdxKccySnv1vMDcVRQg3gb47UNp0p -FRqi/g47Ts+JSLS29X6vqB/iBwKBgQDCU31L4ipLXOWbiJDQVGq5A0N0zAo2j+Jx -Kr3G+R72XRHTBLCvverayCwrI+fvUyvAeUs/trswQ/PmXdkmg40EEJDCJ87ktfEW -MfgRJhloPJkyTf+JKaLlUQwgV7YVtV932EWC8V9Rdcf8rNZ9gt9TiiwGOTCrNDH4 -tL1d1T9OtQKBgAXgw5pyU/Td6Z8SKu+W785dOmL92D04/V/74JFsim978xpvMaZ6 -2knmDji4p9dC417Qvv7NiNTVIUHNAaSFx/Ei5/NQ1Xw9ojirUctjyBq3OEpUm64E -PKVhH/0xC+3MkmqamWFrZc1LW+CxpBwkTtOd6WUmw0eDvCNh+HJA4sQVAoGBAKFN -rDPRCEqGUhFIyuwjJnNswhGxTMj9pnlJgT4ojAr0NldzDTbT7p6sif1FUMDXyPl7 -tXqts7PctBgEzrupduRo28BOSu6OGBDUaZXSikR8CK45EGRKq2yuWeJ+7CYY56YT -X5/Ru81idx7GWUTV3Yr6ppCD6GI0cUaAwK+i02oBAoGAcCho+7uZ0+I2BkR9Fxz/ -gdHgL3Cw5o3x7i1erXXCoxN9YLHwidOtj9w+8IS9dSY9ii08w8LE4BXpgoFe+TGU -yXgEnl8qOUAcXKMu4jRj4LqNaJWXnAZ7J+1WJZ4h7ygGEJh0aYByiUdL5aShs/YJ -CevUdCQxnWbrAySfMEMIXg0= ------END PRIVATE KEY----- diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos/coreos-0.0.1.ebuild b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos/coreos-0.0.1.ebuild index 21b35197a69..4816ab1db3a 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos/coreos-0.0.1.ebuild +++ b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos/coreos-0.0.1.ebuild @@ -76,7 +76,6 @@ RDEPEND="${RDEPEND} amd64? ( app-emulation/xenserver-pv-version app-emulation/xenstore - sys-boot/mokutil )" # sys-devel/gettext: it embeds 'envsubst' binary which is useful for simple file templating. @@ -185,6 +184,7 @@ RDEPEND="${RDEPEND} sys-block/open-iscsi sys-block/parted sys-boot/efibootmgr + sys-boot/mokutil sys-cluster/ipvsadm sys-devel/gettext sys-fs/btrfs-progs diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-devel/board-packages/board-packages-0.0.1-r15.ebuild b/sdk_container/src/third_party/coreos-overlay/coreos-devel/board-packages/board-packages-0.0.1-r16.ebuild similarity index 100% rename from sdk_container/src/third_party/coreos-overlay/coreos-devel/board-packages/board-packages-0.0.1-r15.ebuild rename to sdk_container/src/third_party/coreos-overlay/coreos-devel/board-packages/board-packages-0.0.1-r16.ebuild diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-devel/board-packages/board-packages-0.0.1.ebuild b/sdk_container/src/third_party/coreos-overlay/coreos-devel/board-packages/board-packages-0.0.1.ebuild index 24614e71d84..f1a8b24861c 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos-devel/board-packages/board-packages-0.0.1.ebuild +++ b/sdk_container/src/third_party/coreos-overlay/coreos-devel/board-packages/board-packages-0.0.1.ebuild @@ -26,6 +26,8 @@ RDEPEND=" coreos-base/nova-agent-watcher ) sys-boot/grub + sys-boot/shim + sys-boot/shim-signed app-containers/containerd app-containers/docker app-containers/docker-cli diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-devel/sdk-depends/sdk-depends-0.0.1-r51.ebuild b/sdk_container/src/third_party/coreos-overlay/coreos-devel/sdk-depends/sdk-depends-0.0.1-r52.ebuild similarity index 100% rename from sdk_container/src/third_party/coreos-overlay/coreos-devel/sdk-depends/sdk-depends-0.0.1-r51.ebuild rename to sdk_container/src/third_party/coreos-overlay/coreos-devel/sdk-depends/sdk-depends-0.0.1-r52.ebuild diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-devel/sdk-depends/sdk-depends-0.0.1.ebuild b/sdk_container/src/third_party/coreos-overlay/coreos-devel/sdk-depends/sdk-depends-0.0.1.ebuild index 2d1778bc5c3..b040f4d953f 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos-devel/sdk-depends/sdk-depends-0.0.1.ebuild +++ b/sdk_container/src/third_party/coreos-overlay/coreos-devel/sdk-depends/sdk-depends-0.0.1.ebuild @@ -17,9 +17,11 @@ DEPEND=" app-admin/sudo app-admin/updateservicectl app-arch/pbzip2 - app-crypt/efitools + app-crypt/azure-keyvault-pkcs11 + app-crypt/p11-kit app-crypt/sbsigntools app-emulation/open-vmdk + app-emulation/virt-firmware app-eselect/eselect-python app-misc/jq app-shells/bash-completion @@ -42,7 +44,6 @@ DEPEND=" amd64? ( sys-apps/iucode_tool ) sys-apps/seismograph sys-boot/grub - amd64? ( sys-boot/shim ) sys-firmware/edk2-bin sys-fs/btrfs-progs sys-fs/cryptsetup diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/config/env/sys-boot/grub b/sdk_container/src/third_party/coreos-overlay/coreos/config/env/sys-boot/grub index 759353b3ca2..540af8918c2 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos/config/env/sys-boot/grub +++ b/sdk_container/src/third_party/coreos-overlay/coreos/config/env/sys-boot/grub @@ -1,8 +1,12 @@ -# Bump the flatcar version stated here every time we or Gentoo change patches +# Bump the flatcar version stated here every time we or Red Hat change patches # that modify parts of GRUB that are installed to the boot partition. Reset the # version back to 1 when the upstream GRUB version changes. FLATCAR_VERSION=flatcar2 +# Gentoo's patches conflict with Red Hat's patches, and none of Gentoo's patches +# affect Flatcar, so skip them all. +PATCHES=() + # Adjust the version string for Flatcar. This propagates throughout the source. cros_pre_src_prepare_adjust_version() { sed -i "/AC_INIT/s/\b${PV//./\\.}\b/\0-${FLATCAR_VERSION}/g" configure.ac || die diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/README.md b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/README.md index b405abf5246..e53d7afc3c9 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/README.md +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/README.md @@ -15,6 +15,29 @@ to use a separate repo was scrapped, and two patch files were created. The patch files migrated only the essential commits, and dropped all the other commits, which were either half-baked, or redundant at the point of migration. +From version 2.12, Flatcar has adopted Red Hat's large patch set. This fixes +Secure Boot on arm64 and the TPM Event Log on amd64, among many other things. + +A further two patches are applied on top. One is for additional GPT +functionality, and the other is for extracting the verity root hash from the +initrd. Gentoo's upstream ebuild is used, but Gentoo's patches are discarded +because they conflict and are not relevant to Flatcar. + +Finally, a third patch is applied to fix the fallback mechanism, which was +accidentally broken by Red Hat's patches. This has been submitted to Red Hat in +[rhboot/grub2#195](https://github.com/rhboot/grub2/pull/195). It will hopefully +be merged soon. + +## How to import the Red Hat patches + +Red Hat maintains a fork of GRUB on GitHub with branches for each Fedora release. Generate a diff between the latest upstream release and the latest Fedora branch. + +``` +git clone https://github.com/rhboot/grub2.git grub +cd grub +git diff grub-..fedora- -- . ':(exclude).gitignore' ':(exclude)bootstrap.conf' > grub-2.12-00-redhat.patch +``` + ## Summary of the Flatcar patches The patch starts with adding a new implementation of reading the GPT instead diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-00-redhat.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-00-redhat.patch new file mode 100644 index 00000000000..b2b633fafaa --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-00-redhat.patch @@ -0,0 +1,41291 @@ +diff --git a/Makefile.util.def b/Makefile.util.def +index 9432365a9..ef344f5aa 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -51,6 +51,12 @@ library = { + common = grub-core/partmap/msdos.c; + common = grub-core/fs/proc.c; + common = grub-core/fs/archelp.c; ++ common = grub-core/kern/backtrace.c; ++ ++ x86 = grub-core/kern/i386/backtrace.c; ++ i386_xen = grub-core/kern/i386/backtrace.c; ++ x86_64_xen = grub-core/kern/i386/backtrace.c; ++ arm64 = grub-core/kern/arm64/backtrace.c; + }; + + library = { +@@ -455,6 +461,30 @@ script = { + installdir = grubconf; + }; + ++script = { ++ name = '08_fallback_counting'; ++ common = util/grub.d/08_fallback_counting.in; ++ installdir = grubconf; ++}; ++ ++script = { ++ name = '12_menu_auto_hide'; ++ common = util/grub.d/12_menu_auto_hide.in; ++ installdir = grubconf; ++}; ++ ++script = { ++ name = '14_menu_show_once'; ++ common = util/grub.d/14_menu_show_once.in; ++ installdir = grubconf; ++}; ++ ++script = { ++ name = '01_users'; ++ common = util/grub.d/01_users.in; ++ installdir = grubconf; ++}; ++ + script = { + name = '10_windows'; + common = util/grub.d/10_windows.in; +@@ -497,6 +527,12 @@ script = { + condition = COND_HOST_LINUX; + }; + ++script = { ++ name = '10_reset_boot_success'; ++ common = util/grub.d/10_reset_boot_success.in; ++ installdir = grubconf; ++}; ++ + script = { + name = '10_xnu'; + common = util/grub.d/10_xnu.in; +@@ -517,6 +553,13 @@ script = { + installdir = grubconf; + }; + ++script = { ++ name = '20_ppc_terminfo'; ++ common = util/grub.d/20_ppc_terminfo.in; ++ installdir = grubconf; ++ condition = COND_HOST_LINUX; ++}; ++ + script = { + name = '30_os-prober'; + common = util/grub.d/30_os-prober.in; +@@ -541,6 +584,27 @@ script = { + installdir = grubconf; + }; + ++script = { ++ name = 'grub-systemd-integration.service'; ++ common = util/systemd/grub-systemd-integration.service.in; ++ installdir = systemdunit; ++ condition = COND_HOST_LINUX; ++}; ++ ++script = { ++ name = 'systemd-integration.sh'; ++ common = util/systemd/systemd-integration.sh.in; ++ installdir = grublibexec; ++ condition = COND_HOST_LINUX; ++}; ++ ++script = { ++ name = '10-grub-logind-service.conf'; ++ common = util/systemd/10-grub-logind-service.conf.in; ++ installdir = systemd_logind_service_d; ++ condition = COND_HOST_LINUX; ++}; ++ + program = { + mansection = 1; + name = grub-mkrescue; +@@ -712,6 +776,13 @@ script = { + installdir = sbin; + }; + ++script = { ++ name = grub-get-kernel-settings; ++ common = util/grub-get-kernel-settings.in; ++ mansection = 3; ++ installdir = sbin; ++}; ++ + script = { + name = grub-set-default; + common = util/grub-set-default.in; +@@ -726,6 +797,13 @@ script = { + installdir = sbin; + }; + ++script = { ++ name = grub-set-password; ++ common = util/grub-set-password.in; ++ mansection = 8; ++ installdir = sbin; ++}; ++ + script = { + name = grub-mkconfig_lib; + common = util/grub-mkconfig_lib.in; +@@ -1250,6 +1328,12 @@ script = { + common = tests/luks2_test.in; + }; + ++script = { ++ testcase = native; ++ name = test_asn1; ++ common = tests/test_asn1.in; ++}; ++ + program = { + testcase = native; + name = example_unit_test; +@@ -1360,6 +1444,13 @@ program = { + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + }; + ++script = { ++ name = grub-switch-to-blscfg; ++ common = util/grub-switch-to-blscfg.in; ++ mansection = 8; ++ installdir = sbin; ++}; ++ + program = { + name = grub-glue-efi; + mansection = 1; +@@ -1422,3 +1513,10 @@ program = { + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + }; ++ ++program = { ++ name = grub-set-bootflag; ++ installdir = sbin; ++ mansection = 1; ++ common = util/grub-set-bootflag.c; ++}; +diff --git a/NEWS b/NEWS +index 310130962..e3cfcd569 100644 +--- a/NEWS ++++ b/NEWS +@@ -118,7 +118,7 @@ New in 2.02: + * Prefer pmtimer for TSC calibration. + + * New/improved platform support: +- * New `efifwsetup' and `lsefi' commands on EFI platforms. ++ * New `efifwsetup', `lsefi' and `connectefi` commands on EFI platforms. + * New `cmosdump' and `cmosset' commands on platforms with CMOS support. + * New command `pcidump' for PCI platforms. + * Improve opcode parsing in ACPI halt implementation. +diff --git a/acinclude.m4 b/acinclude.m4 +index fa7840f09..0231e64e3 100644 +--- a/acinclude.m4 ++++ b/acinclude.m4 +@@ -136,6 +136,25 @@ if test "x$grub_cv_prog_ld_build_id_none" = xyes; then + fi + ]) + ++dnl Supply --build-id=sha1 to ld if building modules. ++dnl This suppresses warnings from ld on some systems ++AC_DEFUN([grub_PROG_LD_BUILD_ID_SHA1], ++[AC_MSG_CHECKING([whether linker accepts --build-id=sha1]) ++AC_CACHE_VAL(grub_cv_prog_ld_build_id_sha1, ++[save_LDFLAGS="$LDFLAGS" ++LDFLAGS="$LDFLAGS -Wl,--build-id=sha1" ++AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], ++ [grub_cv_prog_ld_build_id_sha1=yes], ++ [grub_cv_prog_ld_build_id_sha1=no]) ++LDFLAGS="$save_LDFLAGS" ++]) ++AC_MSG_RESULT([$grub_cv_prog_ld_build_id_sha1]) ++ ++if test "x$grub_cv_prog_ld_build_id_sha1" = xyes; then ++ TARGET_LDFLAGS="$TARGET_LDFLAGS -Wl,--build-id=sha1" ++fi ++]) ++ + dnl Check nm + AC_DEFUN([grub_PROG_NM_WORKS], + [AC_MSG_CHECKING([whether nm works]) +diff --git a/conf/Makefile.common b/conf/Makefile.common +index b8f216f6c..f8c2f6bd8 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -41,7 +41,7 @@ CFLAGS_KERNEL = $(CFLAGS_PLATFORM) -ffreestanding + LDFLAGS_KERNEL = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) + CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1 + CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) +-STRIPFLAGS_KERNEL = -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx ++STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx -R .note.gnu.property -R .gnu.build.attributes + if !COND_emu + if COND_HAVE_ASM_USCORE + LDFLAGS_KERNEL += -Wl,--defsym=_malloc=_grub_malloc -Wl,--defsym=_free=_grub_free +@@ -50,32 +50,35 @@ else + endif + endif + +-CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding +-LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r +-CPPFLAGS_MODULE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) +-CCASFLAGS_MODULE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) ++CFLAGS_MODULE = $(TARGET_CFLAGS) $(CFLAGS_PLATFORM) -ffreestanding ++LDFLAGS_MODULE = $(TARGET_LDFLAGS) $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r ++CPPFLAGS_MODULE = $(TARGET_CPPFLAGS) $(CPPFLAGS_DEFAULT) $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) ++CCASFLAGS_MODULE = $(TARGET_CCASFLAGS) $(CCASFLAGS_DEFAULT) $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) + + CFLAGS_IMAGE = $(CFLAGS_PLATFORM) -fno-builtin + LDFLAGS_IMAGE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-S + CPPFLAGS_IMAGE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) + CCASFLAGS_IMAGE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) + +-CFLAGS_PROGRAM = +-LDFLAGS_PROGRAM = +-CPPFLAGS_PROGRAM = +-CCASFLAGS_PROGRAM = ++CFLAGS_PROGRAM = $(CFLAGS_CPU) ++LDFLAGS_PROGRAM = $(LDFLAGS_CPU) ++CPPFLAGS_PROGRAM = $(CPPFLAGS_CPU) ++CCASFLAGS_PROGRAM = $(CCASFLAGS_CPU) + +-CFLAGS_LIBRARY = +-CPPFLAGS_LIBRARY = +-CCASFLAGS_LIBRARY = ++CFLAGS_LIBRARY = $(CFLAGS_CPU) ++CPPFLAGS_LIBRARY = $(CPPFLAGS_CPU) ++CCASFLAGS_LIBRARY = $(CCASFLAGS_CPU) + + # Other variables + + grubconfdir = $(sysconfdir)/grub.d ++grublibexecdir = $(libexecdir)/$(grubdirname) + platformdir = $(pkglibdir)/$(target_cpu)-$(platform) + starfielddir = $(pkgdatadir)/themes/starfield ++systemdunitdir = ${prefix}/lib/systemd/system ++systemd_logind_service_ddir = $(systemdunitdir)/systemd-logind.service.d + +-CFLAGS_GNULIB = -Wno-undef -Wno-sign-compare -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Wno-conversion -Wno-error=attributes ++CFLAGS_GNULIB = -Wno-undef -Wno-error=sign-compare -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Wno-error=attributes -Werror=trampolines -fno-trampolines + CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib + + CFLAGS_POSIX = -fno-builtin +@@ -111,6 +114,7 @@ MOD_FILES = + MODULE_FILES = + MARKER_FILES = + KERNEL_HEADER_FILES = ++EXTRA_DEPS = + + bin_SCRIPTS = + bin_PROGRAMS = +@@ -132,6 +136,9 @@ platform_SCRIPTS = + platform_PROGRAMS = + sbin_SCRIPTS = + sbin_PROGRAMS = ++grublibexec_SCRIPTS = ++systemdunit_SCRIPTS = ++systemd_logind_service_d_SCRIPTS = + + EXTRA_DIST = + CLEANFILES = +diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist +index 5e7126f98..26ac8765e 100644 +--- a/conf/Makefile.extra-dist ++++ b/conf/Makefile.extra-dist +@@ -15,6 +15,9 @@ EXTRA_DIST += docs/man + EXTRA_DIST += docs/autoiso.cfg + EXTRA_DIST += docs/grub.cfg + EXTRA_DIST += docs/osdetect.cfg ++EXTRA_DIST += docs/org.gnu.grub.policy ++EXTRA_DIST += docs/grub-boot-success.service ++EXTRA_DIST += docs/grub-boot-success.timer + + EXTRA_DIST += conf/i386-cygwin-img-ld.sc + +diff --git a/config.h.in b/config.h.in +index 9b1d39971..39f4e5472 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -16,6 +16,7 @@ + /* Define to 1 to enable disk cache statistics. */ + #define DISK_CACHE_STATS @DISK_CACHE_STATS@ + #define BOOT_TIME_STATS @BOOT_TIME_STATS@ ++#define DEBUG_WITH_TIMESTAMPS @DEBUG_WITH_TIMESTAMPS@ + + /* We don't need those. */ + #define MINILZO_CFG_SKIP_LZO_PTR 1 +@@ -63,6 +64,7 @@ + + # define GRUB_TARGET_CPU "@GRUB_TARGET_CPU@" + # define GRUB_PLATFORM "@GRUB_PLATFORM@" ++# define GRUB_RPM_VERSION "@GRUB_RPM_VERSION@" + + # define GRUB_STACK_PROTECTOR_INIT @GRUB_STACK_PROTECTOR_INIT@ + +diff --git a/configure.ac b/configure.ac +index cd667a2eb..4788f3d6a 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -70,6 +70,7 @@ grub_TRANSFORM([grub-install]) + grub_TRANSFORM([grub-mkconfig]) + grub_TRANSFORM([grub-mkfont]) + grub_TRANSFORM([grub-mkimage]) ++grub_TRANSFORM([grub-get-kernel-settings]) + grub_TRANSFORM([grub-glue-efi]) + grub_TRANSFORM([grub-mklayout]) + grub_TRANSFORM([grub-mkpasswd-pbkdf2]) +@@ -77,6 +78,7 @@ grub_TRANSFORM([grub-mkrelpath]) + grub_TRANSFORM([grub-mkrescue]) + grub_TRANSFORM([grub-probe]) + grub_TRANSFORM([grub-reboot]) ++grub_TRANSFORM([grub-set-password]) + grub_TRANSFORM([grub-script-check]) + grub_TRANSFORM([grub-set-default]) + grub_TRANSFORM([grub-sparc64-setup]) +@@ -287,6 +289,19 @@ AC_SUBST(target_cpu) + AC_SUBST(platform) + + # Define default variables ++have_with_rpm_version=n ++AC_ARG_WITH([rpm_version], ++ AS_HELP_STRING([--with-rpm-version=VERSION], ++ [set the rpm package version [[guessed]]]), ++ [have_with_rpm_version=y], ++ [have_with_rpm_version=n]) ++if test x$have_with_rpm_version = xy; then ++ rpm_version="$with_rpm_version" ++else ++ rpm_version="" ++fi ++GRUB_RPM_VERSION="$rpm_version" ++AC_SUBST(GRUB_RPM_VERSION) + + have_with_bootdir=n + AC_ARG_WITH([bootdir], +@@ -319,6 +334,14 @@ AC_SUBST(grubdirname) + AC_DEFINE_UNQUOTED(GRUB_DIR_NAME, "$grubdirname", + [Default grub directory name]) + ++PKG_PROG_PKG_CONFIG ++AS_IF([$($PKG_CONFIG --exists bash-completion)], [ ++ bashcompletiondir=$($PKG_CONFIG --variable=completionsdir bash-completion) ++] , [ ++ bashcompletiondir=${datadir}/bash-completion/completions ++]) ++AC_SUBST(bashcompletiondir) ++ + # + # Checks for build programs. + # +@@ -534,6 +557,9 @@ HOST_CFLAGS="$HOST_CFLAGS $grub_cv_cc_w_extra_flags" + # Check for target programs. + # + ++# This makes sure pkg.m4 is available. ++m4_pattern_forbid([^_?PKG_[A-Z_]+$],[*** pkg.m4 missing, please install pkg-config]) ++ + # Find tools for the target. + if test "x$target_alias" != x && test "x$host_alias" != "x$target_alias"; then + tmp_ac_tool_prefix="$ac_tool_prefix" +@@ -901,11 +927,23 @@ if test "x$target_cpu" = xloongarch64; then + TARGET_CCASFLAGS="$TARGET_CCASFLAGS -Wa,-mla-global-with-abs" + fi + ++# Should grub utils get the host CFLAGS, or the target CFLAGS? ++AC_ARG_WITH([utils], ++ AS_HELP_STRING([--with-utils=host|target|build], ++ [choose which flags to build utilities with. (default=target)]), ++ [have_with_utils=y], ++ [have_with_utils=n]) ++if test x"$have_with_utils" = xy ; then ++ with_utils="$withval" ++else ++ with_utils=target ++fi ++ + # GRUB doesn't use float or doubles at all. Yet some toolchains may decide + # that floats are a good fit to run instead of what's written in the code. + # Given that floating point unit is disabled (if present to begin with) + # when GRUB is running which may result in various hard crashes. +-if test x"$platform" != xemu ; then ++if test x"$platform" != xemu -a x"$with_utils" == xtarget ; then + AC_CACHE_CHECK([for options to get soft-float], grub_cv_target_cc_soft_float, [ + grub_cv_target_cc_soft_float=no + if test "x$target_cpu" = xarm64; then +@@ -1321,6 +1359,26 @@ if test "x$target_cpu" = xarm; then + done + ]) + ++ AC_CACHE_CHECK([for options to disable movt and movw relocations], ++ grub_cv_target_cc_mword_relocations, ++ [grub_cv_target_cc_mword_relocations=no ++ for cand in "-mword-relocations" ; do ++ if test x"$grub_cv_target_cc_mword_relocations" != xno ; then ++ break ++ fi ++ CFLAGS="$TARGET_CFLAGS $cand -Werror" ++ CPPFLAGS="$TARGET_CPPFLAGS" ++ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], ++ [grub_cv_target_cc_mword_relocations="$cand"], ++ []) ++ done ++ ]) ++ if test x"$grub_cv_target_cc_mword_relocations" = xno ; then ++ AC_MSG_ERROR(["your compiler doesn't support disabling movw/movt relocations"]) ++ else ++ TARGET_CFLAGS="$TARGET_CFLAGS $grub_cv_target_cc_mword_relocations" ++ fi ++ + if test x"$grub_cv_target_cc_mno_movt" != xno ; then + # A trick so that clang doesn't see it on link stage + TARGET_CPPFLAGS="$TARGET_CPPFLAGS $grub_cv_target_cc_mno_movt" +@@ -1527,7 +1585,15 @@ grub_PROG_TARGET_CC + if test "x$TARGET_APPLE_LINKER" != x1 ; then + grub_PROG_OBJCOPY_ABSOLUTE + fi ++ ++AC_ARG_ENABLE([build-id], ++ [AS_HELP_STRING([--enable-build-id], ++ [ask the linker to supply build-id notes (default=no)])]) ++if test x$enable_build_id = xyes; then ++grub_PROG_LD_BUILD_ID_SHA1 ++else + grub_PROG_LD_BUILD_ID_NONE ++fi + if test "x$target_cpu" = xi386; then + if test "$platform" != emu && test "x$TARGET_APPLE_LINKER" != x1 ; then + if test ! -z "$TARGET_IMG_LDSCRIPT"; then +@@ -1620,6 +1686,17 @@ else + fi + AC_SUBST([BOOT_TIME_STATS]) + ++AC_ARG_WITH([debug-timestamps], ++ AS_HELP_STRING([--with-debug-timestamps], ++ [prepend debug traces with absolute and relative timestamps])) ++ ++if test x$with_debug_timestamps = xyes; then ++ DEBUG_WITH_TIMESTAMPS=1 ++else ++ DEBUG_WITH_TIMESTAMPS=0 ++fi ++AC_SUBST([DEBUG_WITH_TIMESTAMPS]) ++ + AC_ARG_ENABLE([grub-emu-sdl2], + [AS_HELP_STRING([--enable-grub-emu-sdl2], + [build and install the `grub-emu' debugging utility with SDL2 support (default=guessed)])]) +@@ -1847,7 +1924,7 @@ if test "x$with_dejavufont" = x; then + # search in well-known directories + if test x"$starfield_excuse" = x; then + for ext in pcf pcf.gz bdf bdf.gz ttf ttf.gz; do +- for dir in . /usr/src /usr/share/fonts/X11/misc /usr/share/fonts/truetype/ttf-dejavu /usr/share/fonts/dejavu /usr/share/fonts/truetype /usr/pkg/share/fonts/X11/TTF /usr/local/share/fonts/dejavu /usr/X11R6/lib/X11/fonts/TTF; do ++ for dir in . /usr/src /usr/share/fonts/X11/misc /usr/share/fonts/truetype/ttf-dejavu /usr/share/fonts/dejavu /usr/share/fonts/truetype /usr/pkg/share/fonts/X11/TTF /usr/local/share/fonts/dejavu /usr/X11R6/lib/X11/fonts/TTF /usr/share/fonts/dejavu-sans-fonts; do + if test -f "$dir/DejaVuSans.$ext"; then + DJVU_FONT_SOURCE="$dir/DejaVuSans.$ext" + break 2 +@@ -2081,6 +2158,17 @@ if test x"$enable_werror" != xno ; then + fi + fi + ++AC_ARG_ENABLE([wextra], ++ [AS_HELP_STRING([--disable-wextra], ++ [do not use -Wextra when building GRUB])]) ++if test x"$enable_wextra" != xno ; then ++ TARGET_CFLAGS="$TARGET_CFLAGS -Wextra" ++ HOST_CFLAGS="$HOST_CFLAGS -Wextra" ++fi ++ ++TARGET_CFLAGS="$TARGET_CFLAGS -Werror=trampolines -fno-trampolines -Wno-incompatible-pointer-types" ++HOST_CFLAGS="$HOST_CFLAGS -Werror=trampolines -fno-trampolines -Wno-incompatible-pointer-types" ++ + TARGET_CPP="$TARGET_CC -E" + TARGET_CCAS=$TARGET_CC + +@@ -2090,6 +2178,41 @@ HOST_CPPFLAGS="$HOST_CPPFLAGS -I\$(top_builddir)/include" + TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_srcdir)/include" + TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_builddir)/include" + ++case "$with_utils" in ++ host) ++ UTILS_CFLAGS=$HOST_CFLAGS ++ UTILS_CPPFLAGS=$HOST_CPPFLAGS ++ UTILS_CCASFLAGS=$HOST_CCASFLAGS ++ UTILS_LDFLAGS=$HOST_LDFLAGS ++ ;; ++ target) ++ UTILS_CFLAGS=$TARGET_CFLAGS ++ UTILS_CPPFLAGS=$TARGET_CPPFLAGS ++ UTILS_CCASFLAGS=$TARGET_CCASFLAGS ++ UTILS_LDFLAGS=$TARGET_LDFLAGS ++ ;; ++ build) ++ UTILS_CFLAGS=$BUILD_CFLAGS ++ UTILS_CPPFLAGS=$BUILD_CPPFLAGS ++ UTILS_CCASFLAGS=$BUILD_CCASFLAGS ++ UTILS_LDFLAGS=$BUILD_LDFLAGS ++ ;; ++ *) ++ AC_MSG_ERROR([--with-utils must be either host, target, or build]) ++ ;; ++esac ++AC_MSG_NOTICE([Using $with_utils flags for utilities.]) ++ ++unset CFLAGS ++unset CPPFLAGS ++unset CCASFLAGS ++unset LDFLAGS ++ ++AC_SUBST(UTILS_CFLAGS) ++AC_SUBST(UTILS_CPPFLAGS) ++AC_SUBST(UTILS_CCASFLAGS) ++AC_SUBST(UTILS_LDFLAGS) ++ + GRUB_TARGET_CPU="${target_cpu}" + GRUB_PLATFORM="${platform}" + +@@ -2184,6 +2307,7 @@ AM_CONDITIONAL([COND_APPLE_LINKER], [test x$TARGET_APPLE_LINKER = x1]) + AM_CONDITIONAL([COND_ENABLE_EFIEMU], [test x$enable_efiemu = xyes]) + AM_CONDITIONAL([COND_ENABLE_CACHE_STATS], [test x$DISK_CACHE_STATS = x1]) + AM_CONDITIONAL([COND_ENABLE_BOOT_TIME_STATS], [test x$BOOT_TIME_STATS = x1]) ++AM_CONDITIONAL([COND_DEBUG_WITH_TIMESTAMPS], [test x$DEBUG_WITH_TIMESTAMPS = x1]) + + AM_CONDITIONAL([COND_HAVE_CXX], [test x$HAVE_CXX = xyes]) + +@@ -2285,6 +2409,12 @@ else + echo With boot time statistics: No + fi + ++if [ x"$with_debug_timestamps" = xyes ]; then ++echo Debug traces with timestamps: Yes ++else ++echo Debug traces with timestamps: No ++fi ++ + if [ x"$efiemu_excuse" = x ]; then + echo efiemu runtime: Yes + else +diff --git a/docs/.gitignore b/docs/.gitignore +new file mode 100644 +index 000000000..e1d849ef9 +--- /dev/null ++++ b/docs/.gitignore +@@ -0,0 +1,5 @@ ++/*.in ++/Makefile ++/stamp-1 ++/stamp-vti ++/version*.texi +diff --git a/docs/grub-boot-indeterminate.service b/docs/grub-boot-indeterminate.service +new file mode 100644 +index 000000000..6c8dcb186 +--- /dev/null ++++ b/docs/grub-boot-indeterminate.service +@@ -0,0 +1,11 @@ ++[Unit] ++Description=Mark boot as indeterminate ++DefaultDependencies=false ++Requires=sysinit.target ++After=sysinit.target ++Wants=system-update-pre.target ++Before=system-update-pre.target ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/bin/grub2-editenv - incr boot_indeterminate +diff --git a/docs/grub-boot-success.service b/docs/grub-boot-success.service +new file mode 100644 +index 000000000..80e79584c +--- /dev/null ++++ b/docs/grub-boot-success.service +@@ -0,0 +1,6 @@ ++[Unit] ++Description=Mark boot as successful ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/sbin/grub2-set-bootflag boot_success +diff --git a/docs/grub-boot-success.timer b/docs/grub-boot-success.timer +new file mode 100644 +index 000000000..1d124cccc +--- /dev/null ++++ b/docs/grub-boot-success.timer +@@ -0,0 +1,10 @@ ++[Unit] ++Description=Mark boot as successful after the user session has run 2 minutes ++ConditionUser=!@system ++ConditionVirtualization=!container ++ ++[Timer] ++OnActiveSec=2min ++ ++[Install] ++WantedBy=timers.target +diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi +index 1276c5930..8ad5494f5 100644 +--- a/docs/grub-dev.texi ++++ b/docs/grub-dev.texi +@@ -1,7 +1,7 @@ + \input texinfo + @c -*-texinfo-*- + @c %**start of header +-@setfilename grub-dev.info ++@setfilename grub2-dev.info + @include version-dev.texi + @settitle GNU GRUB Developers Manual @value{VERSION} + @c Unify all our little indices for now. +@@ -32,7 +32,7 @@ Invariant Sections. + + @dircategory Kernel + @direntry +-* grub-dev: (grub-dev). The GRand Unified Bootloader Dev ++* grub2-dev: (grub2-dev). The GRand Unified Bootloader Dev + @end direntry + + @setchapternewpage odd +@@ -996,9 +996,9 @@ declare startup asm file ($cpu_$platform_startup) as well as any other files + (e.g. init.c and callwrap.S) (e.g. $cpu_$platform = kern/$cpu/$platform/init.c). + At this stage you will also need to add dummy dl.c and cache.S with functions + grub_err_t grub_arch_dl_check_header (void *ehdr), grub_err_t +-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c) and +-void grub_arch_sync_caches (void *address, grub_size_t len) (cache.S). They +-won't be used for now. ++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c), grub_uint32_t ++grub_arch_dl_min_alignment (void), and void grub_arch_sync_caches (void ++*address, grub_size_t len) (cache.S). They won't be used for now. + + You will need to create directory include/$cpu/$platform and a file + include/$cpu/types.h. The latter following this template: +diff --git a/docs/grub.texi b/docs/grub.texi +index a225f9a88..096a3cde0 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -1,7 +1,7 @@ + \input texinfo + @c -*-texinfo-*- + @c %**start of header +-@setfilename grub.info ++@setfilename grub2.info + @include version.texi + @settitle GNU GRUB Manual @value{VERSION} + @c Unify all our little indices for now. +@@ -32,15 +32,15 @@ Invariant Sections. + + @dircategory Kernel + @direntry +-* GRUB: (grub). The GRand Unified Bootloader +-* grub-install: (grub)Invoking grub-install. Install GRUB on your drive +-* grub-mkconfig: (grub)Invoking grub-mkconfig. Generate GRUB configuration +-* grub-mkpasswd-pbkdf2: (grub)Invoking grub-mkpasswd-pbkdf2. +-* grub-mkrelpath: (grub)Invoking grub-mkrelpath. +-* grub-mkrescue: (grub)Invoking grub-mkrescue. Make a GRUB rescue image +-* grub-mount: (grub)Invoking grub-mount. Mount a file system using GRUB +-* grub-probe: (grub)Invoking grub-probe. Probe device information +-* grub-script-check: (grub)Invoking grub-script-check. ++* GRUB2: (grub2). The GRand Unified Bootloader ++* grub2-install: (grub2)Invoking grub2-install. Install GRUB on your drive ++* grub2-mkconfig: (grub2)Invoking grub2-mkconfig. Generate GRUB configuration ++* grub2-mkpasswd-pbkdf2: (grub2)Invoking grub2-mkpasswd-pbkdf2. ++* grub2-mkrelpath: (grub2)Invoking grub2-mkrelpath. ++* grub2-mkrescue: (grub2)Invoking grub2-mkrescue. Make a GRUB rescue image ++* grub2-mount: (grub2)Invoking grub2-mount. Mount a file system using GRUB ++* grub2-probe: (grub2)Invoking grub2-probe. Probe device information ++* grub2-script-check: (grub2)Invoking grub2-script-check. + @end direntry + + @setchapternewpage odd +@@ -223,7 +223,7 @@ surprising. + + @item + @file{grub.cfg} is typically automatically generated by +-@command{grub-mkconfig} (@pxref{Simple configuration}). This makes it ++@command{grub2-mkconfig} (@pxref{Simple configuration}). This makes it + easier to handle versioned kernel upgrades. + + @item +@@ -237,7 +237,7 @@ scripting language: variables, conditionals, and loops are available. + @item + A small amount of persistent storage is available across reboots, using the + @command{save_env} and @command{load_env} commands in GRUB and the +-@command{grub-editenv} utility. This is not available in all configurations ++@command{grub2-editenv} utility. This is not available in all configurations + (@pxref{Environment block}). + + @item +@@ -542,7 +542,7 @@ On OS which have device nodes similar to Unix-like OS GRUB tools use the + OS name. E.g. for GNU/Linux: + + @example +-# @kbd{grub-install /dev/sda} ++# @kbd{grub2-install /dev/sda} + @end example + + On AROS we use another syntax. For volumes: +@@ -565,7 +565,7 @@ For disks we use syntax: + E.g. + + @example +-# @kbd{grub-install //:ata.device/0/0} ++# @kbd{grub2-install //:ata.device/0/0} + @end example + + On Windows we use UNC path. For volumes it's typically +@@ -592,7 +592,7 @@ For disks it's + E.g. + + @example +-# @kbd{grub-install \\?\PhysicalDrive0} ++# @kbd{grub2-install \\?\PhysicalDrive0} + @end example + + Beware that you may need to further escape the backslashes depending on your +@@ -602,7 +602,7 @@ When compiled with cygwin support then cygwin drive names are automatically + when needed. E.g. + + @example +-# @kbd{grub-install /dev/sda} ++# @kbd{grub2-install /dev/sda} + @end example + + @node Installation +@@ -615,7 +615,7 @@ from the source tarball, or as a package for your OS. + + After you have done that, you need to install the boot loader on a + drive (floppy or hard disk) by using the utility +-@command{grub-install} (@pxref{Invoking grub-install}) on a UNIX-like OS. ++@command{grub2-install} (@pxref{Invoking grub2-install}) on a UNIX-like OS. + + GRUB comes with boot images, which are normally put in the directory + @file{/usr/lib/grub/-} (for BIOS-based machines +@@ -626,22 +626,22 @@ loader needs to find them (usually @file{/boot}) will be called + the @dfn{boot directory}. + + @menu +-* Installing GRUB using grub-install:: ++* Installing GRUB using grub2-install:: + * Making a GRUB bootable CD-ROM:: + * Device map:: + * BIOS installation:: + @end menu + + +-@node Installing GRUB using grub-install +-@section Installing GRUB using grub-install ++@node Installing GRUB using grub2-install ++@section Installing GRUB using grub2-install + + For information on where GRUB should be installed on PC BIOS platforms, + @pxref{BIOS installation}. + + In order to install GRUB under a UNIX-like OS (such +-as @sc{gnu}), invoke the program @command{grub-install} (@pxref{Invoking +-grub-install}) as the superuser (@dfn{root}). ++as @sc{gnu}), invoke the program @command{grub2-install} (@pxref{Invoking ++grub2-install}) as the superuser (@dfn{root}). + + The usage is basically very simple. You only need to specify one + argument to the program, namely, where to install the boot loader. The +@@ -650,13 +650,13 @@ For example, under Linux the following will install GRUB into the MBR + of the first IDE disk: + + @example +-# @kbd{grub-install /dev/sda} ++# @kbd{grub2-install /dev/sda} + @end example + + Likewise, under GNU/Hurd, this has the same effect: + + @example +-# @kbd{grub-install /dev/hd0} ++# @kbd{grub2-install /dev/hd0} + @end example + + But all the above examples assume that GRUB should put images under +@@ -670,7 +670,7 @@ boot floppy with a filesystem. Here is an example: + # @kbd{mke2fs /dev/fd0} + # @kbd{mount -t ext2 /dev/fd0 /mnt} + # @kbd{mkdir /mnt/boot} +-# @kbd{grub-install --boot-directory=/mnt/boot /dev/fd0} ++# @kbd{grub2-install --boot-directory=/mnt/boot /dev/fd0} + # @kbd{umount /mnt} + @end group + @end example +@@ -682,30 +682,37 @@ floppy instead of exposing the USB drive as a hard disk (they call it + @example + # @kbd{losetup /dev/loop0 /dev/sdb1} + # @kbd{mount /dev/loop0 /mnt/usb} +-# @kbd{grub-install --boot-directory=/mnt/usb/bugbios --force --allow-floppy /dev/loop0} ++# @kbd{grub2-install --boot-directory=/mnt/usb/bugbios --force --allow-floppy /dev/loop0} + @end example + + This install doesn't conflict with standard install as long as they are in + separate directories. + ++Note that @command{grub2-install} is actually just a shell script and the ++real task is done by other tools such as @command{grub2-mkimage}. Therefore, ++you may run those commands directly to install GRUB, without using ++@command{grub2-install}. Don't do that, however, unless you are very familiar ++with the internals of GRUB. Installing a boot loader on a running OS may be ++extremely dangerous. ++ + On EFI systems for fixed disk install you have to mount EFI System Partition. + If you mount it at @file{/boot/efi} then you don't need any special arguments: + + @example +-# @kbd{grub-install} ++# @kbd{grub2-install} + @end example + + Otherwise you need to specify where your EFI System partition is mounted: + + @example +-# @kbd{grub-install --efi-directory=/mnt/efi} ++# @kbd{grub2-install --efi-directory=/mnt/efi} + @end example + + For removable installs you have to use @option{--removable} and specify both + @option{--boot-directory} and @option{--efi-directory}: + + @example +-# @kbd{grub-install --efi-directory=/mnt/usb --boot-directory=/mnt/usb/boot --removable} ++# @kbd{grub2-install --efi-directory=/mnt/usb --boot-directory=/mnt/usb/boot --removable} + @end example + + @node Making a GRUB bootable CD-ROM +@@ -725,10 +732,10 @@ usually also need to include a configuration file @file{grub.cfg} and some + other GRUB modules. + + To make a simple generic GRUB rescue CD, you can use the +-@command{grub-mkrescue} program (@pxref{Invoking grub-mkrescue}): ++@command{grub2-mkrescue} program (@pxref{Invoking grub2-mkrescue}): + + @example +-$ @kbd{grub-mkrescue -o grub.iso} ++$ @kbd{grub2-mkrescue -o grub.iso} + @end example + + You will often need to include other files in your image. To do this, first +@@ -751,7 +758,7 @@ directory @file{iso/}. + Finally, make the image: + + @example +-$ @kbd{grub-mkrescue -o grub.iso iso} ++$ @kbd{grub2-mkrescue -o grub.iso iso} + @end example + + This produces a file named @file{grub.iso}, which then can be burned +@@ -767,7 +774,7 @@ storage devices. + @node Device map + @section The map between BIOS drives and OS devices + +-If the device map file exists, the GRUB utilities (@command{grub-probe}, ++If the device map file exists, the GRUB utilities (@command{grub2-probe}, + etc.) read it to map BIOS drives to OS devices. This file consists of lines + like this: + +@@ -1269,23 +1276,23 @@ need to write the whole thing by hand. + @node Simple configuration + @section Simple configuration handling + +-The program @command{grub-mkconfig} (@pxref{Invoking grub-mkconfig}) ++The program @command{grub2-mkconfig} (@pxref{Invoking grub2-mkconfig}) + generates @file{grub.cfg} files suitable for most cases. It is suitable for + use when upgrading a distribution, and will discover available kernels and + attempt to generate menu entries for them. + +-@command{grub-mkconfig} does have some limitations. While adding extra ++@command{grub2-mkconfig} does have some limitations. While adding extra + custom menu entries to the end of the list can be done by editing +-@file{/etc/grub.d/40_custom} or creating @file{/boot/grub/custom.cfg}, ++@file{/etc/grub.d/40_custom} or creating @file{/boot/grub2/custom.cfg}, + changing the order of menu entries or changing their titles may require + making complex changes to shell scripts stored in @file{/etc/grub.d/}. This + may be improved in the future. In the meantime, those who feel that it + would be easier to write @file{grub.cfg} directly are encouraged to do so + (@pxref{Booting}, and @ref{Shell-like scripting}), and to disable any system +-provided by their distribution to automatically run @command{grub-mkconfig}. ++provided by their distribution to automatically run @command{grub2-mkconfig}. + + The file @file{/etc/default/grub} controls the operation of +-@command{grub-mkconfig}. It is sourced by a shell script, and so must be ++@command{grub2-mkconfig}. It is sourced by a shell script, and so must be + valid POSIX shell input; normally, it will just be a sequence of + @samp{KEY=value} lines, but if the value contains spaces or other special + characters then it must be quoted. For example: +@@ -1323,7 +1330,7 @@ works it's not recommended since titles often contain unstable device names + and may be translated + + If you set this to @samp{saved}, then the default menu entry will be that +-saved by @samp{GRUB_SAVEDEFAULT} or @command{grub-set-default}. This relies on ++saved by @samp{GRUB_SAVEDEFAULT} or @command{grub2-set-default}. This relies on + the environment block, which may not be available in all situations + (@pxref{Environment block}). + +@@ -1334,7 +1341,7 @@ If this option is set to @samp{true}, then, when an entry is selected, save + it as a new default entry for use by future runs of GRUB. This is only + useful if @samp{GRUB_DEFAULT=saved}; it is a separate option because + @samp{GRUB_DEFAULT=saved} is useful without this option, in conjunction with +-@command{grub-set-default}. Unset by default. ++@command{grub2-set-default}. Unset by default. + This option relies on the environment block, which may not be available in + all situations (@pxref{Environment block}). + +@@ -1481,15 +1488,15 @@ intel-uc.img intel-ucode.img amd-uc.img amd-ucode.img early_ucode.cpio microcode + @end example + + @item GRUB_DISABLE_LINUX_UUID +-Normally, @command{grub-mkconfig} will generate menu entries that use ++Normally, @command{grub2-mkconfig} will generate menu entries that use + universally-unique identifiers (UUIDs) to identify the root filesystem to + the Linux kernel, using a @samp{root=UUID=...} kernel parameter. This is + usually more reliable, but in some cases it may not be appropriate. To + disable the use of UUIDs, set this option to @samp{true}. + + @item GRUB_DISABLE_LINUX_PARTUUID +-If @command{grub-mkconfig} cannot identify the root filesystem via its +-universally-unique indentifier (UUID), @command{grub-mkconfig} can use the UUID ++If @command{grub2-mkconfig} cannot identify the root filesystem via its ++universally-unique indentifier (UUID), @command{grub2-mkconfig} can use the UUID + of the partition containing the filesystem to identify the root filesystem to + the Linux kernel via a @samp{root=PARTUUID=...} kernel parameter. This is not + as reliable as using the filesystem UUID, but is more reliable than using the +@@ -1503,7 +1510,7 @@ If this option is set to @samp{true}, disable the generation of recovery + mode menu entries. + + @item GRUB_DISABLE_UUID +-Normally, @command{grub-mkconfig} will generate menu entries that use ++Normally, @command{grub2-mkconfig} will generate menu entries that use + universally-unique identifiers (UUIDs) to identify various filesystems to + search for files. This is usually more reliable, but in some cases it may + not be appropriate. To disable this use of UUIDs, set this option to +@@ -1514,12 +1521,12 @@ not be appropriate. To disable this use of UUIDs, set this option to + @item GRUB_VIDEO_BACKEND + If graphical video support is required, either because the @samp{gfxterm} + graphical terminal is in use or because @samp{GRUB_GFXPAYLOAD_LINUX} is set, +-then @command{grub-mkconfig} will normally load all available GRUB video ++then @command{grub2-mkconfig} will normally load all available GRUB video + drivers and use the one most appropriate for your hardware. If you need to + override this for some reason, then you can set this option. + +-After @command{grub-install} has been run, the available video drivers are +-listed in @file{/boot/grub/video.lst}. ++After @command{grub2-install} has been run, the available video drivers are ++listed in @file{/boot/grub2/video.lst}. + + @item GRUB_GFXMODE + Set the resolution used on the @samp{gfxterm} graphical terminal. Note that +@@ -1552,20 +1559,17 @@ boot sequence. If you have problems, set this option to @samp{text} and + GRUB will tell Linux to boot in normal text mode. + + @item GRUB_DISABLE_OS_PROBER +-The @command{grub-mkconfig} has a feature to use the external +-@command{os-prober} program to discover other operating systems installed on +-the same machine and generate appropriate menu entries for them. It is disabled +-by default since automatic and silent execution of @command{os-prober}, and +-creating boot entries based on that data, is a potential attack vector. Set +-this option to @samp{false} to enable this feature in the +-@command{grub-mkconfig} command. ++Normally, @command{grub2-mkconfig} will try to use the external ++@command{os-prober} program, if installed, to discover other operating ++systems installed on the same system and generate appropriate menu entries ++for them. Set this option to @samp{true} to disable this. + + @item GRUB_OS_PROBER_SKIP_LIST + List of space-separated FS UUIDs of filesystems to be ignored from os-prober + output. For efi chainloaders it's @@ + + @item GRUB_DISABLE_SUBMENU +-Normally, @command{grub-mkconfig} will generate top level menu entry for ++Normally, @command{grub2-mkconfig} will generate top level menu entry for + the kernel with highest version number and put all other found kernels + or alternative menu entries for recovery mode in submenu. For entries returned + by @command{os-prober} first entry will be put on top level and all others +@@ -1573,11 +1577,11 @@ in submenu. If this option is set to @samp{true}, flat menu with all entries + on top level will be generated instead. Changing this option will require + changing existing values of @samp{GRUB_DEFAULT}, @samp{fallback} (@pxref{fallback}) + and @samp{default} (@pxref{default}) environment variables as well as saved +-default entry using @command{grub-set-default} and value used with +-@command{grub-reboot}. ++default entry using @command{grub2-set-default} and value used with ++@command{grub2-reboot}. + + @item GRUB_ENABLE_CRYPTODISK +-If set to @samp{y}, @command{grub-mkconfig} and @command{grub-install} will ++If set to @samp{y}, @command{grub2-mkconfig} and @command{grub2-install} will + check for encrypted disks and generate additional commands needed to access + them during boot. Note that in this case unattended boot is not possible + because GRUB will wait for passphrase to unlock encrypted container. +@@ -1636,7 +1640,7 @@ confusing @samp{GRUB_TIMEOUT_STYLE=countdown} or + + @end table + +-For more detailed customisation of @command{grub-mkconfig}'s output, you may ++For more detailed customisation of @command{grub2-mkconfig}'s output, you may + edit the scripts in @file{/etc/grub.d} directly. + @file{/etc/grub.d/40_custom} is particularly useful for adding entire custom + menu entries; simply type the menu entries you want to add at the end of +@@ -1644,14 +1648,14 @@ that file, making sure to leave at least the first two lines intact. + + @node Root Identifcation Heuristics + @section Root Identifcation Heuristics +-If the target operating system uses the Linux kernel, @command{grub-mkconfig} ++If the target operating system uses the Linux kernel, @command{grub2-mkconfig} + attempts to identify the root file system via a heuristic algoirthm. This + algorithm selects the identification method of the root file system by + considering three factors. The first is if an initrd for the target operating + system is also present. The second is @samp{GRUB_DISABLE_LINUX_UUID} and if set +-to @samp{true}, prevents @command{grub-mkconfig} from identifying the root file ++to @samp{true}, prevents @command{grub2-mkconfig} from identifying the root file + system by its UUID. The third is @samp{GRUB_DISABLE_LINUX_PARTUUID} and if set +-to @samp{true}, prevents @command{grub-mkconfig} from identifying the root file ++to @samp{true}, prevents @command{grub2-mkconfig} from identifying the root file + system via the UUID of its enclosing partition. If the variables are assigned + any other value, that value is considered equivalent to @samp{false}. The + variables are also considered to be set to @samp{false} if they are not set. +@@ -1661,18 +1665,18 @@ filesystem to the initrd. Most initrd images determine the root file system by + checking the Linux kernel's command-line for the @samp{root} key and use its + value as the identification method of the root file system. To improve the + reliability of booting, most initrd images also allow the root file system to be +-identified by its UUID. Because of this behavior, the @command{grub-mkconfig} ++identified by its UUID. Because of this behavior, the @command{grub2-mkconfig} + command will set @samp{root} to @samp{root=UUID=...} to provide the initrd with + the filesystem UUID of the root file system. + + If no initrd is detected or @samp{GRUB_DISABLE_LINUX_UUID} is set to @samp{true} +-then @command{grub-command} will identify the root filesystem by setting the ++then @command{grub2-command} will identify the root filesystem by setting the + kernel command-line variable @samp{root} to @samp{root=PARTUUID=...} unless + @samp{GRUB_DISABLE_LINUX_PARTUUID} is also set to @samp{true}. If + @samp{GRUB_DISABLE_LINUX_PARTUUID} is also set to @samp{true}, +-@command{grub-command} will identify by its Linux device name. ++@command{grub2-command} will identify by its Linux device name. + +-The following table summarizes the behavior of the @command{grub-mkconfig} ++The following table summarizes the behavior of the @command{grub2-mkconfig} + command. + + @multitable {detected} {GRUB_DISABLE_LINUX_PARTUUID} {GRUB_DISABLE_LINUX_UUID} {Linux Root} +@@ -1889,9 +1893,10 @@ than zero; otherwise 0. + @section Multi-boot manual config + + Currently autogenerating config files for multi-boot environments depends on +-os-prober and has several shortcomings. Due to that it is disabled by default. +-It is advised to use the power of GRUB syntax and do it yourself. A possible +-configuration is detailed here, feel free to adjust to your needs. ++os-prober and has several shortcomings. While fixing it is scheduled for the ++next release, meanwhile you can make use of the power of GRUB syntax and do it ++yourself. A possible configuration is detailed here, feel free to adjust to your ++needs. + + First create a separate GRUB partition, big enough to hold GRUB. Some of the + following entries show how to load OS installer images from this same partition, +@@ -1900,7 +1905,7 @@ images as well. + Mount this partition on/mnt/boot and disable GRUB in all OSes and manually + install self-compiled latest GRUB with: + +-@code{grub-install --boot-directory=/mnt/boot /dev/sda} ++@code{grub2-install --boot-directory=/mnt/boot /dev/sda} + + In all the OSes install GRUB tools but disable installing GRUB in bootsector, + so you'll have menu.lst and grub.cfg available for use. Also disable os-prober +@@ -1910,20 +1915,20 @@ use by setting: + + in /etc/default/grub + +-Then write a grub.cfg (/mnt/boot/grub/grub.cfg): ++Then write a grub.cfg (/mnt/boot/grub2/grub.cfg): + + @example + + menuentry "OS using grub2" @{ + insmod xfs + search --set=root --label OS1 --hint hd0,msdos8 +- configfile /boot/grub/grub.cfg ++ configfile /boot/grub2/grub.cfg + @} + + menuentry "OS using grub2-legacy" @{ + insmod ext2 + search --set=root --label OS2 --hint hd0,msdos6 +- legacy_configfile /boot/grub/menu.lst ++ legacy_configfile /boot/grub2/menu.lst + @} + + menuentry "Windows XP" @{ +@@ -1986,15 +1991,15 @@ GRUB supports embedding a configuration file directly into the core image, + so that it is loaded before entering normal mode. This is useful, for + example, when it is not straightforward to find the real configuration file, + or when you need to debug problems with loading that file. +-@command{grub-install} uses this feature when it is not using BIOS disk ++@command{grub2-install} uses this feature when it is not using BIOS disk + functions or when installing to a different disk from the one containing + @file{/boot/grub}, in which case it needs to use the @command{search} + command (@pxref{search}) to find @file{/boot/grub}. + + To embed a configuration file, use the @option{-c} option to +-@command{grub-mkimage}. The file is copied into the core image, so it may ++@command{grub2-mkimage}. The file is copied into the core image, so it may + reside anywhere on the file system, and may be removed after running +-@command{grub-mkimage}. ++@command{grub2-mkimage}. + + After the embedded configuration file (if any) is executed, GRUB will load + the @samp{normal} module (@pxref{normal}), which will then read the real +@@ -2029,13 +2034,13 @@ included in the core image: + @example + @group + search.fs_label grub root +-if [ -e /boot/grub/example/test1.cfg ]; then ++if [ -e /boot/grub2/example/test1.cfg ]; then + set prefix=($root)/boot/grub +- configfile /boot/grub/example/test1.cfg ++ configfile /boot/grub2/example/test1.cfg + else +- if [ -e /boot/grub/example/test2.cfg ]; then ++ if [ -e /boot/grub2/example/test2.cfg ]; then + set prefix=($root)/boot/grub +- configfile /boot/grub/example/test2.cfg ++ configfile /boot/grub2/example/test2.cfg + else + echo "Could not find an example configuration file!" + fi +@@ -2559,7 +2564,7 @@ grub-mknetdir --net-directory=/srv/tftp --subdir=/boot/grub -d /usr/lib/grub/i38 + @end group + @end example + +-Then follow instructions printed out by grub-mknetdir on configuring your DHCP ++Then follow instructions printed out by grub2-mknetdir on configuring your DHCP + server. + + The grub.cfg file is placed in the same directory as the path output by +@@ -2762,7 +2767,7 @@ team are: + @end table + + To take full advantage of this function, install GRUB into the MBR +-(@pxref{Installing GRUB using grub-install}). ++(@pxref{Installing GRUB using grub2-install}). + + If you have a laptop which has a similar feature and not in the above list + could you figure your address and contribute? +@@ -2823,7 +2828,7 @@ bytes. + The sole function of @file{boot.img} is to read the first sector of the core + image from a local disk and jump to it. Because of the size restriction, + @file{boot.img} cannot understand any file system structure, so +-@command{grub-install} hardcodes the location of the first sector of the ++@command{grub2-install} hardcodes the location of the first sector of the + core image into @file{boot.img} when installing GRUB. + + @item diskboot.img +@@ -2853,7 +2858,7 @@ images. + + @item core.img + This is the core image of GRUB. It is built dynamically from the kernel +-image and an arbitrary list of modules by the @command{grub-mkimage} ++image and an arbitrary list of modules by the @command{grub2-mkimage} + program. Usually, it contains enough modules to access @file{/boot/grub}, + and loads everything else (including menu handling, the ability to load + target operating systems, and so on) from the file system at run-time. The +@@ -2905,7 +2910,7 @@ GRUB 2 has no single Stage 2 image. Instead, it loads modules from + In GRUB 2, images for booting from CD-ROM drives are now constructed using + @file{cdboot.img} and @file{core.img}, making sure that the core image + contains the @samp{iso9660} module. It is usually best to use the +-@command{grub-mkrescue} program for this. ++@command{grub2-mkrescue} program for this. + + @item nbgrub + There is as yet no equivalent for @file{nbgrub} in GRUB 2; it was used by +@@ -3073,8 +3078,8 @@ There are two ways to specify files, by @dfn{absolute file name} and by + + An absolute file name resembles a Unix absolute file name, using + @samp{/} for the directory separator (not @samp{\} as in DOS). One +-example is @samp{(hd0,1)/boot/grub/grub.cfg}. This means the file +-@file{/boot/grub/grub.cfg} in the first partition of the first hard ++example is @samp{(hd0,1)/boot/grub2/grub.cfg}. This means the file ++@file{/boot/grub2/grub.cfg} in the first partition of the first hard + disk. If you omit the device name in an absolute file name, GRUB uses + GRUB's @dfn{root device} implicitly. So if you set the root device to, + say, @samp{(hd1,1)} by the command @samp{set root=(hd1,1)} (@pxref{set}), +@@ -3082,8 +3087,8 @@ then @code{/boot/kernel} is the same as @code{(hd1,1)/boot/kernel}. + + On ZFS filesystem the first path component must be + @var{volume}@samp{@@}[@var{snapshot}]. +-So @samp{/rootvol@@snap-129/boot/grub/grub.cfg} refers to file +-@samp{/boot/grub/grub.cfg} in snapshot of volume @samp{rootvol} with name ++So @samp{/rootvol@@snap-129/boot/grub2/grub.cfg} refers to file ++@samp{/boot/grub2/grub.cfg} in snapshot of volume @samp{rootvol} with name + @samp{snap-129}. Trailing @samp{@@} after volume name is mandatory even if + snapshot name is omitted. + +@@ -3270,6 +3275,7 @@ These variables have special meaning to GRUB. + + @menu + * biosnum:: ++* check_appended_signatures:: + * check_signatures:: + * chosen:: + * cmdpath:: +@@ -3334,11 +3340,18 @@ For an alternative approach which also changes BIOS drive mappings for the + chain-loaded system, @pxref{drivemap}. + + ++@node check_appended_signatures ++@subsection check_appended_signatures ++ ++This variable controls whether GRUB enforces appended signature validation on ++certain loaded files. @xref{Using appended signatures}. ++ ++ + @node check_signatures + @subsection check_signatures + +-This variable controls whether GRUB enforces digital signature +-validation on loaded files. @xref{Using digital signatures}. ++This variable controls whether GRUB enforces GPG-style digital signature ++validation on loaded files. @xref{Using GPG-style digital signatures}. + + @node chosen + @subsection chosen +@@ -3502,7 +3515,7 @@ The more recent release of Minix would then be identified as + @samp{other>minix>minix-3.4.0}. + + This variable is often set by @samp{GRUB_DEFAULT} (@pxref{Simple +-configuration}), @command{grub-set-default}, or @command{grub-reboot}. ++configuration}), @command{grub2-set-default}, or @command{grub2-reboot}. + + + @node fallback +@@ -3592,7 +3605,7 @@ If this variable is set, it names the language code that the + example, French would be named as @samp{fr}, and Simplified Chinese as + @samp{zh_CN}. + +-@command{grub-mkconfig} (@pxref{Simple configuration}) will try to set a ++@command{grub2-mkconfig} (@pxref{Simple configuration}) will try to set a + reasonable default for this variable based on the system locale. + + +@@ -3600,10 +3613,10 @@ reasonable default for this variable based on the system locale. + @subsection locale_dir + + If this variable is set, it names the directory where translation files may +-be found (@pxref{gettext}), usually @file{/boot/grub/locale}. Otherwise, ++be found (@pxref{gettext}), usually @file{/boot/grub2/locale}. Otherwise, + internationalization is disabled. + +-@command{grub-mkconfig} (@pxref{Simple configuration}) will set a reasonable ++@command{grub2-mkconfig} (@pxref{Simple configuration}) will set a reasonable + default for this variable if internationalization is needed and any + translation files are available. + +@@ -3740,7 +3753,7 @@ input. The default is not to pause output. + + The location of the @samp{/boot/grub} directory as an absolute file name + (@pxref{File name syntax}). This is normally set by GRUB at startup based +-on information provided by @command{grub-install}. GRUB modules are ++on information provided by @command{grub2-install}. GRUB modules are + dynamically loaded from this directory, so it must be set correctly in order + for many parts of GRUB to work. + +@@ -3852,17 +3865,17 @@ GRUB provides an ``environment block'' which can be used to save a small + amount of state. + + The environment block is a preallocated 1024-byte file, which normally lives +-in @file{/boot/grub/grubenv} (although you should not assume this). At boot ++in @file{/boot/grub2/grubenv} (although you should not assume this). At boot + time, the @command{load_env} command (@pxref{load_env}) loads environment + variables from it, and the @command{save_env} (@pxref{save_env}) command + saves environment variables to it. From a running system, the +-@command{grub-editenv} utility can be used to edit the environment block. ++@command{grub2-editenv} utility can be used to edit the environment block. + + For safety reasons, this storage is only available when installed on a plain + disk (no LVM or RAID), using a non-checksumming filesystem (no ZFS), and + using BIOS or EFI functions (no ATA, USB or IEEE1275). + +-@command{grub-mkconfig} uses this facility to implement ++@command{grub2-mkconfig} uses this facility to implement + @samp{GRUB_SAVEDEFAULT} (@pxref{Simple configuration}). + + @node Modules +@@ -4357,6 +4370,7 @@ you forget a command, you can run the command @command{help} + * date:: Display or set current date and time + * devicetree:: Load a device tree blob + * distrust:: Remove a pubkey from trusted keys ++* distrust_certificate:: Remove a certificate from the list of trusted certificates + * drivemap:: Map a drive to another + * echo:: Display a line of text + * efitextmode:: Set/Get text output mode resolution +@@ -4373,6 +4387,7 @@ you forget a command, you can run the command @command{help} + * hexdump:: Show raw contents of a file or memory + * insmod:: Insert a module + * keystatus:: Check key modifier status ++* list_certificates:: List trusted certificates + * list_env:: List variables in environment block + * list_trusted:: List trusted public keys + * load_env:: Load variables from environment block +@@ -4411,8 +4426,10 @@ you forget a command, you can run the command @command{help} + * test:: Check file types and compare values + * true:: Do nothing, successfully + * trust:: Add public key to list of trusted keys ++* trust_certificate:: Add an x509 certificate to the list of trusted certificates + * unset:: Unset an environment variable + @comment * vbeinfo:: List available video modes ++* verify_appended:: Verify appended digital signature + * verify_detached:: Verify detached digital signature + * videoinfo:: List available video modes + * wrmsr:: Write values to model-specific registers +@@ -4752,9 +4769,28 @@ These keys are used to validate signatures when environment variable + @code{check_signatures} is set to @code{enforce} + (@pxref{check_signatures}), and by some invocations of + @command{verify_detached} (@pxref{verify_detached}). @xref{Using +-digital signatures}, for more information. ++GPG-style digital signatures}, for more information. + @end deffn + ++ ++@node distrust_certificate ++@subsection distrust_certificate ++ ++@deffn Command distrust_certificate cert_number ++Remove the x509 certificate numbered @var{cert_number} from GRUB's keyring of ++trusted x509 certificates for verifying appended signatures. ++ ++@var{cert_number} is the certificate number as listed by ++@command{list_certificates} (@pxref{list_certificates}). ++ ++These certificates are used to validate appended signatures when environment ++variable @code{check_appended_signatures} is set to @code{enforce} or ++@code{forced} (@pxref{check_appended_signatures}), and by ++@command{verify_appended} (@pxref{verify_appended}). See ++@xref{Using appended signatures} for more information. ++@end deffn ++ ++ + @node drivemap + @subsection drivemap + +@@ -4924,7 +4960,7 @@ Translate @var{string} into the current language. + + The current language code is stored in the @samp{lang} variable in GRUB's + environment (@pxref{lang}). Translation files in MO format are read from +-@samp{locale_dir} (@pxref{locale_dir}), usually @file{/boot/grub/locale}. ++@samp{locale_dir} (@pxref{locale_dir}), usually @file{/boot/grub2/locale}. + @end deffn + + +@@ -5031,6 +5067,21 @@ only if checking key modifier status is supported. + @end deffn + + ++@node list_certificates ++@subsection list_certificates ++ ++@deffn Command list_certificates ++List all x509 certificates trusted by GRUB for validating appended signatures. ++The output is a numbered list of certificates, showing the certificate's serial ++number and Common Name. ++ ++The certificate number can be used as an argument to ++@command{distrust_certificate} (@pxref{distrust_certificate}). ++ ++See @xref{Using appended signatures} for more information. ++@end deffn ++ ++ + @node list_env + @subsection list_env + +@@ -5050,7 +5101,7 @@ The output is in GPG's v4 key fingerprint format (i.e., the output of + @code{gpg --fingerprint}). The least significant four bytes (last + eight hexadecimal digits) can be used as an argument to + @command{distrust} (@pxref{distrust}). +-@xref{Using digital signatures}, for more information about uses for ++@xref{Using GPG-style digital signatures}, for more information about uses for + these keys. + @end deffn + +@@ -5085,8 +5136,13 @@ When used with care, @option{--skip-sig} and the whitelist enable an + administrator to configure a system to boot only signed + configurations, but to allow the user to select from among multiple + configurations, and to enable ``one-shot'' boot attempts and +-``savedefault'' behavior. @xref{Using digital signatures}, for more ++``savedefault'' behavior. @xref{Using GPG-style digital signatures}, for more + information. ++ ++Extra care should be taken when combining this command with appended signatures ++(@pxref{Using appended signatures}), as this file is not validated by an ++appended signature and could set @code{check_appended_signatures=no} if GRUB is ++not in @pxref{Lockdown} mode. + @end deffn + + +@@ -5276,7 +5332,7 @@ Define a user named @var{user} with password @var{clear-password}. + + @deffn Command password_pbkdf2 user hashed-password + Define a user named @var{user} with password hash @var{hashed-password}. +-Use @command{grub-mkpasswd-pbkdf2} (@pxref{Invoking grub-mkpasswd-pbkdf2}) ++Use @command{grub2-mkpasswd-pbkdf2} (@pxref{Invoking grub2-mkpasswd-pbkdf2}) + to generate password hashes. @xref{Security}. + @end deffn + +@@ -5457,7 +5513,7 @@ read. It is possible to modify a digitally signed environment block + file from within GRUB using this command, such that its signature will + no longer be valid on subsequent boots. Care should be taken in such + advanced configurations to avoid rendering the system +-unbootable. @xref{Using digital signatures}, for more information. ++unbootable. @xref{Using GPG-style digital signatures}, for more information. + @end deffn + + +@@ -5873,11 +5929,32 @@ signatures when environment variable @code{check_signatures} is set to + must itself be properly signed. The @option{--skip-sig} option can be + used to disable signature-checking when reading @var{pubkey_file} + itself. It is expected that @option{--skip-sig} is useful for testing +-and manual booting. @xref{Using digital signatures}, for more ++and manual booting. @xref{Using GPG-style digital signatures}, for more + information. + @end deffn + + ++@node trust_certificate ++@subsection trust_certificate ++ ++@deffn Command trust_certificate x509_certificate ++Read an DER-formatted x509 certificate from the file @var{x509_certificate} ++and add it to GRUB's internal list of trusted x509 certificates. These ++certificates are used to validate appended signatures when the environment ++variable @code{check_appended_signatures} is set to @code{enforce} or ++@code{forced}. ++ ++Note that if @code{check_appended_signatures} is set to @code{enforce} or ++@code{forced} when @command{trust_certificate} is executed, then ++@var{x509_certificate} must itself bear an appended signature. (It is not ++sufficient that @var{x509_certificate} be signed by a trusted certificate ++according to the x509 rules: grub does not include support for validating ++signatures within x509 certificates themselves.) ++ ++See @xref{Using appended signatures} for more information. ++@end deffn ++ ++ + @node unset + @subsection unset + +@@ -5896,6 +5973,18 @@ only on PC BIOS platforms. + @end deffn + @end ignore + ++@node verify_appended ++@subsection verify_appended ++ ++@deffn Command verify_appended file ++Verifies an appended signature on @var{file} against the trusted certificates ++known to GRUB (See @pxref{list_certificates}, @pxref{trust_certificate}, and ++@pxref{distrust_certificate}). ++ ++Exit code @code{$?} is set to 0 if the signature validates ++successfully. If validation fails, it is set to a non-zero value. ++See @xref{Using appended signatures}, for more information. ++@end deffn + + @node verify_detached + @subsection verify_detached +@@ -5914,7 +6003,7 @@ tried. + + Exit code @code{$?} is set to 0 if the signature validates + successfully. If validation fails, it is set to a non-zero value. +-@xref{Using digital signatures}, for more information. ++@xref{Using GPG-style digital signatures}, for more information. + @end deffn + + @node videoinfo +@@ -5950,6 +6039,7 @@ Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). + * net_add_dns:: Add a DNS server + * net_add_route:: Add routing entry + * net_bootp:: Perform a bootp/DHCP autoconfiguration ++* net_bootp6:: Perform a DHCPv6 autoconfiguration + * net_del_addr:: Remove IP address from interface + * net_del_dns:: Remove a DNS server + * net_del_route:: Remove a route entry +@@ -6075,6 +6165,22 @@ Sets environment variable @samp{net_}@var{}@samp{_boot_file} + + @end deffn + ++@node net_bootp6 ++@subsection net_bootp6 ++ ++@deffn Command net_bootp6 [@var{card}] ++Perform configuration of @var{card} using DHCPv6 protocol. If no card name is ++specified, try to configure all existing cards. If configuration was ++successful, interface with name @var{card}@samp{:dhcp6} and configured address ++is added to @var{card}. ++ ++@table @samp ++@item 1 (Domain Name Server) ++Adds all servers from option value to the list of servers used during name ++resolution. ++@end table ++ ++@end deffn + + @node net_get_dhcp_option + @subsection net_get_dhcp_option +@@ -6375,12 +6481,14 @@ environment variables and commands are listed in the same order. + @chapter Security + + @menu +-* Authentication and authorisation:: Users and access control +-* Using digital signatures:: Booting digitally signed code +-* UEFI secure boot and shim:: Booting digitally signed PE files +-* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation +-* Measured Boot:: Measuring boot components +-* Lockdown:: Lockdown when booting on a secure setup ++* Authentication and authorisation:: Users and access control ++* Using GPG-style digital signatures:: Booting digitally signed code ++* Using appended signatures:: An alternative approach to booting digitally signed code ++* UEFI secure boot and shim:: Booting digitally signed PE files ++* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation ++* Measured Boot:: Measuring boot components ++* Lockdown:: Lockdown when booting on a secure setup ++* Signing GRUB itself:: Ensuring the integrity of the GRUB core image + @end menu + + @node Authentication and authorisation +@@ -6402,8 +6510,8 @@ The @samp{password} (@pxref{password}) and @samp{password_pbkdf2} + which has an associated password. @samp{password} sets the password in + plain text, requiring @file{grub.cfg} to be secure; @samp{password_pbkdf2} + sets the password hashed using the Password-Based Key Derivation Function +-(RFC 2898), requiring the use of @command{grub-mkpasswd-pbkdf2} +-(@pxref{Invoking grub-mkpasswd-pbkdf2}) to generate password hashes. ++(RFC 2898), requiring the use of @command{grub2-mkpasswd-pbkdf2} ++(@pxref{Invoking grub2-mkpasswd-pbkdf2}) to generate password hashes. + + In order to enable authentication support, the @samp{superusers} environment + variable must be set to a list of usernames, separated by any of spaces, +@@ -6448,18 +6556,18 @@ menuentry "May be run by user1 or a superuser" --users user1 @{ + @end group + @end example + +-The @command{grub-mkconfig} program does not yet have built-in support for ++The @command{grub2-mkconfig} program does not yet have built-in support for + generating configuration files with authentication. You can use + @file{/etc/grub.d/40_custom} to add simple superuser authentication, by + adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2} + commands. + +-@node Using digital signatures +-@section Using digital signatures in GRUB ++@node Using GPG-style digital signatures ++@section Using GPG-style digital signatures in GRUB + + GRUB's @file{core.img} can optionally provide enforcement that all files + subsequently read from disk are covered by a valid digital signature. +-This document does @strong{not} cover how to ensure that your ++This section does @strong{not} cover how to ensure that your + platform's firmware (e.g., Coreboot) validates @file{core.img}. + + If environment variable @code{check_signatures} +@@ -6474,8 +6582,18 @@ validation fails, then file @file{foo} cannot be opened. This failure + may halt or otherwise impact the boot process. + + An initial trusted public key can be embedded within the GRUB @file{core.img} +-using the @code{--pubkey} option to @command{grub-install} +-(@pxref{Invoking grub-install}). ++using the @code{--pubkey} option to @command{grub2-install} ++(@pxref{Invoking grub2-install}). ++ ++@comment Unfortunately --pubkey is not yet supported by grub2-install, ++@comment but we should not bring up internal detail grub2-mkimage here ++@comment in the user guide (as opposed to developer's manual). ++ ++@comment An initial trusted public key can be embedded within the GRUB ++@comment @file{core.img} using the @code{--pubkey} option to ++@comment @command{grub2-mkimage} (@pxref{Invoking grub2-install}). Presently it ++@comment is necessary to write a custom wrapper around @command{grub2-mkimage} ++@comment using the @code{--grub-mkimage} flag to @command{grub2-install}. + + GRUB uses GPG-style detached signatures (meaning that a file + @file{foo.sig} will be produced when file @file{foo} is signed), and +@@ -6495,8 +6613,8 @@ gpg --detach-sign /path/to/file + For successful validation of all of GRUB's subcomponents and the + loaded OS kernel, they must all be signed. One way to accomplish this + is the following (after having already produced the desired +-@file{grub.cfg} file, e.g., by running @command{grub-mkconfig} +-(@pxref{Invoking grub-mkconfig}): ++@file{grub.cfg} file, e.g., by running @command{grub2-mkconfig} ++(@pxref{Invoking grub2-mkconfig}): + + @example + @group +@@ -6518,7 +6636,7 @@ See also: @ref{check_signatures}, @ref{verify_detached}, @ref{trust}, + Note that internally signature enforcement is controlled by setting + the environment variable @code{check_signatures} equal to + @code{enforce}. Passing one or more @code{--pubkey} options to +-@command{grub-mkimage} implicitly defines @code{check_signatures} ++@command{grub2-mkimage} implicitly defines @code{check_signatures} + equal to @code{enforce} in @file{core.img} prior to processing any + configuration files. + +@@ -6538,6 +6656,86 @@ or BIOS) configuration to cause the machine to boot from a different + (attacker-controlled) device. GRUB is at best only one link in a + secure boot chain. + ++@node Using appended signatures ++@section Using appended signatures in GRUB ++ ++GRUB supports verifying Linux-style 'appended signatures' for secure boot. ++Appended signatures are PKCS#7 messages containing a signature over the ++contents of a file, plus some metadata, appended to the end of a file. A file ++with an appended signature ends with the magic string: ++ ++@example ++~Module signature appended~\n ++@end example ++ ++where @code{\n} represents the line-feed character, @code{0x0a}. ++ ++Certificates can be managed at boot time using the @pxref{trust_certificate}, ++@pxref{distrust_certificate} and @pxref{list_certificates} commands. ++Certificates can also be built in to the core image using the @code{--x509} ++parameter to @command{grub-install} or @command{grub-mkimage}. ++ ++A file can be explictly verified using the @pxref{verify_appended} command. ++ ++Only signatures made with the SHA-256 or SHA-512 hash algorithm are supported, ++and only RSA signatures are supported. ++ ++A file can be signed with the @command{sign-file} utility supplied with the ++Linux kernel source. For example, if you have @code{signing.key} as the private ++key and @code{certificate.der} as the x509 certificate containing the public key: ++ ++@example ++sign-file SHA256 signing.key certificate.der vmlinux vmlinux.signed ++@end example ++ ++Enforcement of signature verification is controlled by the ++@code{check_appended_signatures} variable. ++ ++@itemize ++@item @samp{no}: no verification is performed. This is the default when GRUB ++ is not in @pxref{Lockdown} mode. ++@item @samp{enforce}: verification is performed. Verification can be disabled ++ by setting the variable back to @samp{no}. ++@item @samp{forced}: verification is performed and cannot be disabled. This is ++ set when GRUB is in Lockdown when the appendedsig module is loaded. ++@end itemize ++ ++Unlike GPG-style signatures, not all files loaded by GRUB are required to be ++signed. Once verification is turned on, the following file types will have ++appended signatures verified: ++ ++@itemize ++@item Linux kernels ++@item GRUB modules, except those built into the core image ++@item Any new certificate files to be trusted ++@end itemize ++ ++ACPI tables and Device Tree images will not be checked for appended signatures ++but must be verified by another mechanism such as GPG-style signatures before ++they will be loaded. ++ ++Unless lockdown mode is enabled, signature checking does @strong{not} ++stop an attacker with console access from dropping manually to the GRUB ++console and executing: ++ ++@example ++set check_appended_signatures=no ++@end example ++ ++Refer to the section on password-protecting GRUB (@pxref{Authentication ++and authorisation}) for more information on preventing this. ++ ++Additionally, unless lockdown mode is enabled: ++ ++@itemize ++@item Special care must be taken around the @command{loadenv} command, which ++ can be used to turn off @code{check_appended_signature}. ++ ++@item If the grub configuration file is loaded from the disk, anyone who can ++ modify the file on disk can turn off @code{check_appended_signature}. ++ Consider embedding the configuration into the core grub image. ++@end itemize ++ + @node UEFI secure boot and shim + @section UEFI secure boot and shim support + +@@ -6566,7 +6764,7 @@ UTF-8 strings as comma-separated values (CSV). See + @uref{https://github.com/rhboot/shim/blob/main/SBAT.md} for more details. + + To add a data section containing the SBAT information into the binary, the +-@option{--sbat} option of @command{grub-mkimage} command should be used. The content ++@option{--sbat} option of @command{grub2-mkimage} command should be used. The content + of a CSV file, encoded with UTF-8, is copied as is to the .sbat data section into + the generated EFI binary. The CSV file can be stored anywhere on the file system. + +@@ -6616,12 +6814,73 @@ platforms. + @section Lockdown when booting on a secure setup + + The GRUB can be locked down when booted on a secure boot environment, for example +-if the UEFI secure boot is enabled. On a locked down configuration, the GRUB will +-be restricted and some operations/commands cannot be executed. ++if UEFI or Power secure boot is enabled. On a locked down configuration, the ++GRUB will be restricted and some operations/commands cannot be executed. + + The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down. + Otherwise it does not exit. + ++@node Signing GRUB itself ++@section Signing GRUB itself ++ ++To ensure a complete secure-boot chain, there must be a way for the code that ++loads GRUB to verify the integrity of the core image. ++ ++This is ultimately platform-specific and individual platforms can define their ++own mechanisms. However, there are general-purpose mechanisms that can be used ++with GRUB. ++ ++@section Signing GRUB for UEFI secure boot ++ ++On UEFI platforms, @file{core.img} is a PE binary. Therefore, it can be signed ++with a tool such as @command{pesign} or @command{sbsign}. Refer to the ++suggestions in @pxref{UEFI secure boot and shim} to ensure that the final ++image works under UEFI secure boot and can maintain the secure-boot chain. It ++will also be necessary to enrol the public key used into a relevant firmware ++key database. ++ ++@section Signing GRUB with an appended signature ++ ++The @file{core.elf} itself can be signed with a Linux kernel module-style ++appended signature. ++ ++To support IEEE1275 platforms where the boot image is often loaded directly ++from a disk partition rather than from a file system, the @file{core.elf} ++can specify the size and location of the appended signature with an ELF ++note added by @command{grub-install}. ++ ++An image can be signed this way using the @command{sign-file} command from ++the Linux kernel: ++ ++@example ++@group ++# grub.key is your private key and certificate.der is your public key ++ ++# Determine the size of the appended signature. It depends on the signing ++# certificate and the hash algorithm ++touch empty ++sign-file SHA256 grub.key certificate.der empty empty.sig ++SIG_SIZE=`stat -c '%s' empty.sig` ++rm empty empty.sig ++ ++# Build a grub image with $SIG_SIZE reserved for the signature ++grub-install --appended-signature-size $SIG_SIZE --modules="..." ... ++ ++# Replace the reserved size with a signature: ++# cut off the last $SIG_SIZE bytes with truncate's minus modifier ++truncate -s -$SIG_SIZE /boot/grub/powerpc-ieee1275/core.elf core.elf.unsigned ++# sign the trimmed file with an appended signature, restoring the correct size ++sign-file SHA256 grub.key certificate.der core.elf.unsigned core.elf.signed ++ ++# Don't forget to install the signed image as required ++# (e.g. on powerpc-ieee1275, to the PReP partition) ++@end group ++@end example ++ ++As with UEFI secure boot, it is necessary to build in the required modules, ++or sign them separately. ++ ++ + @node Platform limitations + @chapter Platform limitations + +@@ -6977,10 +7236,10 @@ Required files are: + + GRUB's normal start-up procedure involves setting the @samp{prefix} + environment variable to a value set in the core image by +-@command{grub-install}, setting the @samp{root} variable to match, loading ++@command{grub2-install}, setting the @samp{root} variable to match, loading + the @samp{normal} module from the prefix, and running the @samp{normal} + command (@pxref{normal}). This command is responsible for reading +-@file{/boot/grub/grub.cfg}, running the menu, and doing all the useful ++@file{/boot/grub2/grub.cfg}, running the menu, and doing all the useful + things GRUB is supposed to do. + + If, instead, you only get a rescue shell, this usually means that GRUB +@@ -7006,8 +7265,8 @@ normal + + However, any problem that leaves you in the rescue shell probably means that + GRUB was not correctly installed. It may be more useful to try to reinstall +-it properly using @kbd{grub-install @var{device}} (@pxref{Invoking +-grub-install}). When doing this, there are a few things to remember: ++it properly using @kbd{grub2-install @var{device}} (@pxref{Invoking ++grub2-install}). When doing this, there are a few things to remember: + + @itemize @bullet{} + @item +@@ -7019,7 +7278,7 @@ is usually better to use UUIDs or file system labels and avoid depending on + drive ordering entirely. + + @item +-At least on BIOS systems, if you tell @command{grub-install} to install GRUB ++At least on BIOS systems, if you tell @command{grub2-install} to install GRUB + to a partition but GRUB has already been installed in the master boot + record, then the GRUB installation in the partition will be ignored. + +@@ -7054,33 +7313,40 @@ bootability on other machines. + @chapter User-space utilities + + @menu +-* Invoking grub-install:: How to use the GRUB installer +-* Invoking grub-mkconfig:: Generate a GRUB configuration file +-* Invoking grub-mkpasswd-pbkdf2:: ++* Invoking grub2-install:: How to use the GRUB installer ++* Invoking grub2-mkconfig:: Generate a GRUB configuration file ++* Invoking grub2-mkpasswd-pbkdf2:: + Generate GRUB password hashes +-* Invoking grub-mkrelpath:: Make system path relative to its root +-* Invoking grub-mkrescue:: Make a GRUB rescue image +-* Invoking grub-mount:: Mount a file system using GRUB +-* Invoking grub-probe:: Probe device information for GRUB +-* Invoking grub-script-check:: Check GRUB script file for syntax errors ++* Invoking grub2-mkrelpath:: Make system path relative to its root ++* Invoking grub2-mkrescue:: Make a GRUB rescue image ++* Invoking grub2-mount:: Mount a file system using GRUB ++* Invoking grub2-probe:: Probe device information for GRUB ++* Invoking grub2-script-check:: Check GRUB script file for syntax errors + @end menu + + +-@node Invoking grub-install +-@section Invoking grub-install ++@node Invoking grub2-install ++@section Invoking grub2-install + +-The program @command{grub-install} generates a GRUB core image using +-@command{grub-mkimage} and installs it on your system. You must specify the ++The program @command{grub2-install} generates a GRUB core image using ++@command{grub2-mkimage} and installs it on your system. You must specify the + device name on which you want to install GRUB, like this: + + @example +-grub-install @var{install_device} ++grub2-install @var{install_device} + @end example + + The device name @var{install_device} is an OS device name or a GRUB + device name. + +-@command{grub-install} accepts the following options: ++In order to support UEFI Secure Boot, the resulting GRUB EFI binary must ++be signed by a recognized private key. For this reason, for EFI ++platforms, most distributions also ship prebuilt GRUB EFI binaries ++signed by a distribution-specific private key. In this case, however, ++@command{grub2-install} should not be used because it would overwrite ++the signed EFI binary. ++ ++@command{grub2-install} accepts the following options: + + @table @option + @item --help +@@ -7096,13 +7362,13 @@ separate partition or a removable disk. + If this option is not specified then it defaults to @file{/boot}, so + + @example +-@kbd{grub-install /dev/sda} ++@kbd{grub2-install /dev/sda} + @end example + + is equivalent to + + @example +-@kbd{grub-install --boot-directory=/boot/ /dev/sda} ++@kbd{grub2-install --boot-directory=/boot/ /dev/sda} + @end example + + Here is an example in which you have a separate @dfn{boot} partition which is +@@ -7110,16 +7376,16 @@ mounted on + @file{/mnt/boot}: + + @example +-@kbd{grub-install --boot-directory=/mnt/boot /dev/sdb} ++@kbd{grub2-install --boot-directory=/mnt/boot /dev/sdb} + @end example + + @item --recheck +-Recheck the device map, even if @file{/boot/grub/device.map} already ++Recheck the device map, even if @file{/boot/grub2/device.map} already + exists. You should use this option whenever you add/remove a disk + into/from your computer. + + @item --no-rs-codes +-By default on x86 BIOS systems, @command{grub-install} will use some ++By default on x86 BIOS systems, @command{grub2-install} will use some + extra space in the bootloader embedding area for Reed-Solomon + error-correcting codes. This enables GRUB to still boot successfully + if some blocks are corrupted. The exact amount of protection offered +@@ -7132,17 +7398,17 @@ installation}) where GRUB does not reside in any unpartitioned space + outside of the MBR. Disable the Reed-Solomon codes with this option. + @end table + +-@node Invoking grub-mkconfig +-@section Invoking grub-mkconfig ++@node Invoking grub2-mkconfig ++@section Invoking grub2-mkconfig + +-The program @command{grub-mkconfig} generates a configuration file for GRUB ++The program @command{grub2-mkconfig} generates a configuration file for GRUB + (@pxref{Simple configuration}). + + @example +-grub-mkconfig -o /boot/grub/grub.cfg ++grub2-mkconfig -o /boot/grub2/grub.cfg + @end example + +-@command{grub-mkconfig} accepts the following options: ++@command{grub2-mkconfig} accepts the following options: + + @table @option + @item --help +@@ -7158,17 +7424,17 @@ it to standard output. + @end table + + +-@node Invoking grub-mkpasswd-pbkdf2 +-@section Invoking grub-mkpasswd-pbkdf2 ++@node Invoking grub2-mkpasswd-pbkdf2 ++@section Invoking grub2-mkpasswd-pbkdf2 + +-The program @command{grub-mkpasswd-pbkdf2} generates password hashes for ++The program @command{grub2-mkpasswd-pbkdf2} generates password hashes for + GRUB (@pxref{Security}). + + @example +-grub-mkpasswd-pbkdf2 ++grub2-mkpasswd-pbkdf2 + @end example + +-@command{grub-mkpasswd-pbkdf2} accepts the following options: ++@command{grub2-mkpasswd-pbkdf2} accepts the following options: + + @table @option + @item -c @var{number} +@@ -7186,23 +7452,23 @@ Length of the salt. Defaults to 64. + @end table + + +-@node Invoking grub-mkrelpath +-@section Invoking grub-mkrelpath ++@node Invoking grub2-mkrelpath ++@section Invoking grub2-mkrelpath + +-The program @command{grub-mkrelpath} makes a file system path relative to ++The program @command{grub2-mkrelpath} makes a file system path relative to + the root of its containing file system. For instance, if @file{/usr} is a + mount point, then: + + @example +-$ @kbd{grub-mkrelpath /usr/share/grub/unicode.pf2} ++$ @kbd{grub2-mkrelpath /usr/share/grub/unicode.pf2} + @samp{/share/grub/unicode.pf2} + @end example + + This is mainly used internally by other GRUB utilities such as +-@command{grub-mkconfig} (@pxref{Invoking grub-mkconfig}), but may ++@command{grub2-mkconfig} (@pxref{Invoking grub2-mkconfig}), but may + occasionally also be useful for debugging. + +-@command{grub-mkrelpath} accepts the following options: ++@command{grub2-mkrelpath} accepts the following options: + + @table @option + @item --help +@@ -7213,17 +7479,17 @@ Print the version number of GRUB and exit. + @end table + + +-@node Invoking grub-mkrescue +-@section Invoking grub-mkrescue ++@node Invoking grub2-mkrescue ++@section Invoking grub2-mkrescue + +-The program @command{grub-mkrescue} generates a bootable GRUB rescue image ++The program @command{grub2-mkrescue} generates a bootable GRUB rescue image + (@pxref{Making a GRUB bootable CD-ROM}). + + @example +-grub-mkrescue -o grub.iso ++grub2-mkrescue -o grub.iso + @end example + +-All arguments not explicitly listed as @command{grub-mkrescue} options are ++All arguments not explicitly listed as @command{grub2-mkrescue} options are + passed on directly to @command{xorriso} in @command{mkisofs} emulation mode. + Options passed to @command{xorriso} will normally be interpreted as + @command{mkisofs} options; if the option @samp{--} is used, then anything +@@ -7235,10 +7501,10 @@ commonly used to add extra files to the image: + @example + mkdir -p disk/boot/grub + @r{(add extra files to @file{disk/boot/grub})} +-grub-mkrescue -o grub.iso disk ++grub2-mkrescue -o grub.iso disk + @end example + +-@command{grub-mkrescue} accepts the following options: ++@command{grub2-mkrescue} accepts the following options: + + @table @option + @item --help +@@ -7266,15 +7532,15 @@ Use @var{file} as the @command{xorriso} program, rather than the built-in + default. + + @item --grub-mkimage=@var{file} +-Use @var{file} as the @command{grub-mkimage} program, rather than the ++Use @var{file} as the @command{grub2-mkimage} program, rather than the + built-in default. + @end table + + +-@node Invoking grub-mount +-@section Invoking grub-mount ++@node Invoking grub2-mount ++@section Invoking grub2-mount + +-The program @command{grub-mount} performs a read-only mount of any file ++The program @command{grub2-mount} performs a read-only mount of any file + system or file system image that GRUB understands, using GRUB's file system + drivers via FUSE. (It is only available if FUSE development files were + present when GRUB was built.) This has a number of uses: +@@ -7306,13 +7572,13 @@ even if nobody has yet written a FUSE module specifically for that file + system type. + @end itemize + +-Using @command{grub-mount} is normally as simple as: ++Using @command{grub2-mount} is normally as simple as: + + @example +-grub-mount /dev/sda1 /mnt ++grub2-mount /dev/sda1 /mnt + @end example + +-@command{grub-mount} must be given one or more images and a mount point as ++@command{grub2-mount} must be given one or more images and a mount point as + non-option arguments (if it is given more than one image, it will treat them + as a RAID set), and also accepts the following options: + +@@ -7334,13 +7600,13 @@ Show debugging output for conditions matching @var{string}. + @item -K prompt|@var{file} + @itemx --zfs-key=prompt|@var{file} + Load a ZFS encryption key. If you use @samp{prompt} as the argument, +-@command{grub-mount} will read a passphrase from the terminal; otherwise, it ++@command{grub2-mount} will read a passphrase from the terminal; otherwise, it + will read key material from the specified file. + + @item -r @var{device} + @itemx --root=@var{device} + Set the GRUB root device to @var{device}. You do not normally need to set +-this; @command{grub-mount} will automatically set the root device to the ++this; @command{grub2-mount} will automatically set the root device to the + root of the supplied file system. + + If @var{device} is just a number, then it will be treated as a partition +@@ -7349,7 +7615,7 @@ an entire disk in @file{disk.img}, then you can use this command to mount + its second partition: + + @example +-grub-mount -r 2 disk.img mount-point ++grub2-mount -r 2 disk.img mount-point + @end example + + @item -v +@@ -7358,18 +7624,18 @@ Print verbose messages. + @end table + + +-@node Invoking grub-probe +-@section Invoking grub-probe ++@node Invoking grub2-probe ++@section Invoking grub2-probe + +-The program @command{grub-probe} probes device information for a given path ++The program @command{grub2-probe} probes device information for a given path + or device. + + @example +-grub-probe --target=fs /boot/grub +-grub-probe --target=drive --device /dev/sda1 ++grub2-probe --target=fs /boot/grub ++grub2-probe --target=drive --device /dev/sda1 + @end example + +-@command{grub-probe} must be given a path or device as a non-option ++@command{grub2-probe} must be given a path or device as a non-option + argument, and also accepts the following options: + + @table @option +@@ -7382,16 +7648,16 @@ Print the version number of GRUB and exit. + @item -d + @itemx --device + If this option is given, then the non-option argument is a system device +-name (such as @samp{/dev/sda1}), and @command{grub-probe} will print ++name (such as @samp{/dev/sda1}), and @command{grub2-probe} will print + information about that device. If it is not given, then the non-option + argument is a filesystem path (such as @samp{/boot/grub}), and +-@command{grub-probe} will print information about the device containing that ++@command{grub2-probe} will print information about the device containing that + part of the filesystem. + + @item -m @var{file} + @itemx --device-map=@var{file} + Use @var{file} as the device map (@pxref{Device map}) rather than the +-default, usually @samp{/boot/grub/device.map}. ++default, usually @samp{/boot/grub2/device.map}. + + @item -t @var{target} + @itemx --target=@var{target} +@@ -7444,19 +7710,19 @@ Print verbose messages. + @end table + + +-@node Invoking grub-script-check +-@section Invoking grub-script-check ++@node Invoking grub2-script-check ++@section Invoking grub2-script-check + +-The program @command{grub-script-check} takes a GRUB script file ++The program @command{grub2-script-check} takes a GRUB script file + (@pxref{Shell-like scripting}) and checks it for syntax errors, similar to + commands such as @command{sh -n}. It may take a @var{path} as a non-option + argument; if none is supplied, it will read from standard input. + + @example +-grub-script-check /boot/grub/grub.cfg ++grub2-script-check /boot/grub2/grub.cfg + @end example + +-@command{grub-script-check} accepts the following options: ++@command{grub2-script-check} accepts the following options: + + @table @option + @item --help +diff --git a/docs/man/grub-get-kernel-settings.h2m b/docs/man/grub-get-kernel-settings.h2m +new file mode 100644 +index 000000000..b8051f01f +--- /dev/null ++++ b/docs/man/grub-get-kernel-settings.h2m +@@ -0,0 +1,2 @@ ++[NAME] ++grub-get-kernel-settings \- Evaluate the system's kernel installation settings for use while making a grub configuration file +diff --git a/docs/man/grub-set-bootflag.h2m b/docs/man/grub-set-bootflag.h2m +new file mode 100644 +index 000000000..94ec0b92e +--- /dev/null ++++ b/docs/man/grub-set-bootflag.h2m +@@ -0,0 +1,2 @@ ++[NAME] ++grub-set-bootflag \- set a bootflag in the GRUB environment block +diff --git a/docs/man/grub-set-password.h2m b/docs/man/grub-set-password.h2m +new file mode 100644 +index 000000000..10ee82f4d +--- /dev/null ++++ b/docs/man/grub-set-password.h2m +@@ -0,0 +1,2 @@ ++[NAME] ++grub-set-password \- generate the user.cfg file containing the hashed grub bootloader password +diff --git a/docs/man/grub-switch-to-blscfg.h2m b/docs/man/grub-switch-to-blscfg.h2m +new file mode 100644 +index 000000000..fa341426a +--- /dev/null ++++ b/docs/man/grub-switch-to-blscfg.h2m +@@ -0,0 +1,2 @@ ++[NAME] ++grub-switch-to-blscfg \- switch to using BLS config files +diff --git a/gentpl.py b/gentpl.py +index bfab2113a..0f8d009ef 100644 +--- a/gentpl.py ++++ b/gentpl.py +@@ -52,6 +52,7 @@ GROUPS["riscv32"] = [ "riscv32_efi" ] + GROUPS["riscv64"] = [ "riscv64_efi" ] + + # Groups based on firmware ++GROUPS["pc"] = [ "i386_pc" ] + GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi", + "loongarch64_efi", "riscv32_efi", "riscv64_efi" ] + GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ] +@@ -594,11 +595,21 @@ def platform_conditional(platform, closure): + # }; + # + def foreach_enabled_platform(defn, closure): ++ enabled = False ++ disabled = False + if 'enable' in defn: ++ enabled = True + for platform in GRUB_PLATFORMS: + if platform_tagged(defn, platform, "enable"): + platform_conditional(platform, closure) +- else: ++ ++ if 'disable' in defn: ++ disabled = True ++ for platform in GRUB_PLATFORMS: ++ if not platform_tagged(defn, platform, "disable"): ++ platform_conditional(platform, closure) ++ ++ if not enabled and not disabled: + for platform in GRUB_PLATFORMS: + platform_conditional(platform, closure) + +@@ -631,6 +642,9 @@ def platform_values(defn, platform, suffix): + def extra_dist(defn): + return foreach_value(defn, "extra_dist", lambda value: value + " ") + ++def extra_dep(defn): ++ return foreach_value(defn, "depends", lambda value: value + " ") ++ + def platform_sources(defn, p): return platform_values(defn, p, "") + def platform_nodist_sources(defn, p): return platform_values(defn, p, "_nodist") + +@@ -657,6 +671,8 @@ def first_time(defn, snippet): + def is_platform_independent(defn): + if 'enable' in defn: + return False ++ if 'disable' in defn: ++ return False + for suffix in [ "", "_nodist" ]: + template = platform_values(defn, GRUB_PLATFORMS[0], suffix) + for platform in GRUB_PLATFORMS[1:]: +@@ -686,10 +702,10 @@ def module(defn, platform): + var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform) + " ## platform sources") + var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + " ## platform nodist sources") + var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform)) +- var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_MODULE) " + platform_cflags(defn, platform)) +- var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_MODULE) " + platform_ldflags(defn, platform)) +- var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform)) +- var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform)) ++ var_set(cname(defn) + "_CFLAGS", "$(CFLAGS_MODULE) " + platform_cflags(defn, platform)) ++ var_set(cname(defn) + "_LDFLAGS", "$(LDFLAGS_MODULE) " + platform_ldflags(defn, platform)) ++ var_set(cname(defn) + "_CPPFLAGS", "$(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform)) ++ var_set(cname(defn) + "_CCASFLAGS", "$(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform)) + var_set(cname(defn) + "_DEPENDENCIES", "$(TARGET_OBJ2ELF) " + platform_dependencies(defn, platform)) + + gvar_add("dist_noinst_DATA", extra_dist(defn)) +@@ -699,6 +715,10 @@ def module(defn, platform): + gvar_add("MOD_FILES", name + ".mod") + gvar_add("MARKER_FILES", name + ".marker") + gvar_add("CLEANFILES", name + ".marker") ++ ++ for dep in defn.find_all("depends"): ++ gvar_add("EXTRA_DEPS", "depends " + name + " " + dep + ":") ++ + output(""" + """ + name + """.marker: $(""" + cname(defn) + """_SOURCES) $(nodist_""" + cname(defn) + """_SOURCES) + $(TARGET_CPP) -DGRUB_LST_GENERATOR $(CPPFLAGS_MARKER) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(""" + cname(defn) + """_CPPFLAGS) $(CPPFLAGS) $^ > $@.new || (rm -f $@; exit 1) +diff --git a/grub-core/.gitignore b/grub-core/.gitignore +new file mode 100644 +index 000000000..2acce2811 +--- /dev/null ++++ b/grub-core/.gitignore +@@ -0,0 +1,16 @@ ++/*.lst ++/Makefile ++/Makefile.gcry.def ++/unidata.c ++/build-grub-module-verifier ++/gdb_grub ++/genmod.sh ++/gensyminfo.sh ++/gentrigtables ++/gmodule.pl ++/grub_script.tab.[ch] ++/modinfo.sh ++/rs_decoder.h ++/symlist.c ++/symlist.h ++/trigtables.c +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index f18550c1c..aa172391f 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -66,6 +66,7 @@ CLEANFILES += grub_script.yy.c grub_script.yy.h + + include $(srcdir)/Makefile.core.am + ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/backtrace.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cache.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/command.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/device.h +@@ -75,6 +76,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/sb.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env_private.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/err.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fdt.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/file.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fs.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i18n.h +@@ -454,8 +456,15 @@ crypto.lst: $(srcdir)/lib/libgcrypt-grub/cipher/crypto.lst + platform_DATA += crypto.lst + CLEANFILES += crypto.lst + +-syminfo.lst: gensyminfo.sh kernel_syms.lst $(top_srcdir)/grub-core/extra_deps.lst $(MODULE_FILES) +- cat kernel_syms.lst $(top_srcdir)/grub-core/extra_deps.lst > $@.new ++extra_deps.lst: ++ @echo $(EXTRA_DEPS) | sed "s/\s*:\s*/\n/g" > $@ ++ ++syminfo.lst: gensyminfo.sh kernel_syms.lst extra_deps.lst $(MODULE_FILES) ++ if ! [ -f extra_deps.lst ] ; then \ ++ echo Missing extra_deps.lst ; \ ++ echo $(EXTRA_DEPS) | sed "s/\s*:\s*/\n/g" > extra_deps.lst ; \ ++ fi ++ cat kernel_syms.lst extra_deps.lst > $@.new + for m in $(MODULE_FILES); do \ + sh $< $$m >> $@.new || exit 1; \ + done +@@ -465,7 +474,7 @@ syminfo.lst: gensyminfo.sh kernel_syms.lst $(top_srcdir)/grub-core/extra_deps.ls + moddep.lst: syminfo.lst genmoddep.awk video.lst + cat $< | sort | $(AWK) -f $(srcdir)/genmoddep.awk > $@ || (rm -f $@; exit 1) + platform_DATA += moddep.lst +-CLEANFILES += config.log syminfo.lst moddep.lst ++CLEANFILES += config.log syminfo.lst moddep.lst extra_deps.lst + + $(MOD_FILES): %.mod : genmod.sh moddep.lst %.module$(EXEEXT) build-grub-module-verifier$(BUILD_EXEEXT) + TARGET_OBJ2ELF=@TARGET_OBJ2ELF@ sh $^ $@ +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 1571421d7..6ff483534 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -99,7 +99,7 @@ kernel = { + i386_xen_pvh_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x100000'; + + mips_loongson_ldflags = '-Wl,-Ttext,0x80200000'; +- powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x200000'; ++ powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x400000'; + sparc64_ieee1275_ldflags = '-Wl,-Ttext,0x4400'; + mips_arc_ldflags = '-Wl,-Ttext,$(TARGET_LINK_ADDR)'; + mips_qemu_mips_ldflags = '-Wl,-Ttext,0x80200000'; +@@ -153,6 +153,12 @@ kernel = { + common = kern/rescue_reader.c; + common = kern/term.c; + common = kern/verifiers.c; ++ common = kern/backtrace.c; ++ ++ x86 = kern/i386/backtrace.c; ++ i386_xen = kern/i386/backtrace.c; ++ x86_64_xen = kern/i386/backtrace.c; ++ arm64 = kern/arm64/backtrace.c; + + noemu = kern/compiler-rt.c; + noemu = kern/mm.c; +@@ -182,7 +188,6 @@ kernel = { + arm_coreboot = kern/arm/coreboot/init.c; + arm_coreboot = kern/arm/coreboot/timer.c; + arm_coreboot = kern/arm/coreboot/coreboot.S; +- arm_coreboot = lib/fdt.c; + arm_coreboot = bus/fdt.c; + arm_coreboot = term/ps2.c; + arm_coreboot = term/arm/pl050.c; +@@ -219,6 +224,7 @@ kernel = { + efi = kern/efi/acpi.c; + efi = kern/efi/sb.c; + efi = kern/lockdown.c; ++ efi = lib/envblk.c; + i386_coreboot = kern/i386/pc/acpi.c; + i386_multiboot = kern/i386/pc/acpi.c; + i386_coreboot = kern/acpi.c; +@@ -331,6 +337,7 @@ kernel = { + powerpc_ieee1275 = kern/powerpc/cache.S; + powerpc_ieee1275 = kern/powerpc/dl.c; + powerpc_ieee1275 = kern/powerpc/compiler-rt.S; ++ powerpc_ieee1275 = kern/lockdown.c; + + sparc64_ieee1275 = kern/sparc64/cache.S; + sparc64_ieee1275 = kern/sparc64/dl.c; +@@ -363,6 +370,8 @@ kernel = { + riscv64 = kern/riscv/cache_flush.S; + riscv64 = kern/riscv/dl.c; + ++ fdt = lib/fdt.c; ++ + emu = disk/host.c; + emu = kern/emu/cache_s.S; + emu = kern/emu/hostdisk.c; +@@ -409,6 +418,11 @@ kernel = { + extra_dist = kern/mips/cache_flush.S; + }; + ++module = { ++ name = increment; ++ common = commands/increment.c; ++}; ++ + program = { + name = grub-emu; + mansection = 1; +@@ -590,6 +604,11 @@ image = { + enable = mips_loongson; + }; + ++module = { ++ name = version; ++ common = commands/version.c; ++}; ++ + module = { + name = disk; + common = lib/disk.c; +@@ -824,6 +843,12 @@ module = { + enable = efi; + }; + ++module = { ++ name = efienv; ++ common = commands/efi/env.c; ++ enable = efi; ++}; ++ + module = { + name = efifwsetup; + efi = commands/efi/efifwsetup.c; +@@ -836,11 +861,27 @@ module = { + enable = efi; + }; + ++module = { ++ name = connectefi; ++ common = commands/efi/connectefi.c; ++ enable = efi; ++}; ++ + module = { + name = blocklist; + common = commands/blocklist.c; + }; + ++module = { ++ name = blscfg; ++ common = commands/blscfg.c; ++ common = commands/loadenv.h; ++ enable = powerpc_ieee1275; ++ enable = efi; ++ enable = i386_pc; ++ enable = emu; ++}; ++ + module = { + name = boot; + common = commands/boot.c; +@@ -975,6 +1016,18 @@ module = { + cppflags = '-I$(srcdir)/lib/posix_wrap'; + }; + ++module = { ++ name = appendedsig; ++ common = commands/appendedsig/appendedsig.c; ++ common = commands/appendedsig/x509.c; ++ common = commands/appendedsig/pkcs7.c; ++ common = commands/appendedsig/asn1util.c; ++ common = commands/appendedsig/gnutls_asn1_tab.c; ++ common = commands/appendedsig/pkix_asn1_tab.c; ++ cflags = '$(CFLAGS_POSIX)'; ++ cppflags = '-I$(srcdir)/lib/posix_wrap'; ++}; ++ + module = { + name = hdparm; + common = commands/hdparm.c; +@@ -1008,6 +1061,7 @@ module = { + module = { + name = loadenv; + common = commands/loadenv.c; ++ common = commands/loadenv.h; + common = lib/envblk.c; + }; + +@@ -1777,12 +1831,6 @@ module = { + }; + + +-module = { +- name = linux16; +- common = loader/i386/pc/linux.c; +- enable = x86; +-}; +- + module = { + name = ntldr; + i386_pc = loader/i386/pc/ntldr.c; +@@ -1838,10 +1886,9 @@ module = { + + module = { + name = linux; +- x86 = loader/i386/linux.c; + i386_xen_pvh = loader/i386/linux.c; + xen = loader/i386/xen.c; +- i386_pc = lib/i386/pc/vesa_modes_table.c; ++ i386_pc = loader/i386/pc/linux.c; + i386_xen_pvh = lib/i386/pc/vesa_modes_table.c; + mips = loader/mips/linux.c; + powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c; +@@ -1854,8 +1901,12 @@ module = { + loongarch64 = loader/efi/linux.c; + riscv32 = loader/efi/linux.c; + riscv64 = loader/efi/linux.c; ++ i386_efi = loader/i386/efi/linux.c; + i386_efi = loader/efi/linux.c; ++ i386_efi = loader/i386/linux.c; ++ x86_64_efi = loader/i386/efi/linux.c; + x86_64_efi = loader/efi/linux.c; ++ x86_64_efi = loader/i386/linux.c; + emu = loader/emu/linux.c; + common = loader/linux.c; + common = lib/cmdline.c; +@@ -1864,7 +1915,6 @@ module = { + module = { + name = fdt; + efi = loader/efi/fdt.c; +- common = lib/fdt.c; + enable = fdt; + }; + +@@ -2165,6 +2215,12 @@ module = { + common = tests/setjmp_test.c; + }; + ++module = { ++ name = appended_signature_test; ++ common = tests/appended_signature_test.c; ++ common = tests/appended_signatures.h; ++}; ++ + module = { + name = signature_test; + common = tests/signature_test.c; +@@ -2338,6 +2394,12 @@ module = { + common = hook/datehook.c; + }; + ++module = { ++ name = efi_netfs; ++ common = net/efi/efi_netfs.c; ++ enable = efi; ++}; ++ + module = { + name = net; + common = net/net.c; +@@ -2351,6 +2413,12 @@ module = { + common = net/ethernet.c; + common = net/arp.c; + common = net/netbuff.c; ++ efi = net/efi/net.c; ++ efi = net/efi/http.c; ++ efi = net/efi/pxe.c; ++ efi = net/efi/ip4_config.c; ++ efi = net/efi/ip6_config.c; ++ efi = net/efi/dhcp.c; + }; + + module = { +@@ -2392,6 +2460,7 @@ module = { + common = commands/legacycfg.c; + common = lib/legacy_parse.c; + emu = lib/i386/pc/vesa_modes_table.c; ++ i386_pc = lib/i386/pc/vesa_modes_table.c; + i386_efi = lib/i386/pc/vesa_modes_table.c; + x86_64_efi = lib/i386/pc/vesa_modes_table.c; + xen = lib/i386/pc/vesa_modes_table.c; +@@ -2440,15 +2509,12 @@ module = { + + module = { + name = backtrace; +- x86 = lib/i386/backtrace.c; +- i386_xen_pvh = lib/i386/backtrace.c; +- i386_xen = lib/i386/backtrace.c; +- x86_64_xen = lib/i386/backtrace.c; +- common = lib/backtrace.c; ++ common = commands/backtrace.c; + enable = x86; + enable = i386_xen_pvh; + enable = i386_xen; + enable = x86_64_xen; ++ enable = arm64; + }; + + module = { +@@ -2525,6 +2591,14 @@ module = { + cppflags = '$(CPPFLAGS_GCRY)'; + }; + ++module = { ++ name = pkcs1_v15; ++ common = lib/pkcs1_v15.c; ++ ++ cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare'; ++ cppflags = '$(CPPFLAGS_GCRY)'; ++}; ++ + module = { + name = all_video; + common = lib/fake_module.c; +@@ -2594,4 +2668,33 @@ module = { + name = bli; + efi = commands/bli.c; + enable = efi; ++ depends = part_gpt; ++}; ++ ++module = { ++ name = asn1; ++ common = lib/libtasn1/lib/decoding.c; ++ common = lib/libtasn1/lib/coding.c; ++ common = lib/libtasn1/lib/element.c; ++ common = lib/libtasn1/lib/structure.c; ++ common = lib/libtasn1/lib/parser_aux.c; ++ common = lib/libtasn1/lib/gstr.c; ++ common = lib/libtasn1/lib/errors.c; ++ common = lib/libtasn1_wrap/wrap.c; ++ cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)'; ++ // -Wno-type-limits comes from libtasn1's configure.ac ++ cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1/lib -Wno-type-limits'; ++}; ++ ++module = { ++ name = test_asn1; ++ common = lib/libtasn1_wrap/tests/CVE-2018-1000654.c; ++ common = lib/libtasn1_wrap/tests/object-id-decoding.c; ++ common = lib/libtasn1_wrap/tests/object-id-encoding.c; ++ common = lib/libtasn1_wrap/tests/octet-string.c; ++ common = lib/libtasn1_wrap/tests/reproducers.c; ++ common = lib/libtasn1_wrap/tests/Test_overflow.c; ++ common = lib/libtasn1_wrap/tests/Test_simple.c; ++ common = lib/libtasn1_wrap/tests/Test_strings.c; ++ common = lib/libtasn1_wrap/wrap_tests.c; + }; +diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c +new file mode 100644 +index 000000000..1b8a80780 +--- /dev/null ++++ b/grub-core/commands/appendedsig/appendedsig.c +@@ -0,0 +1,645 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020-2021 IBM Corporation. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "appendedsig.h" ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++const char magic[] = "~Module signature appended~\n"; ++ ++/* ++ * This structure is extracted from scripts/sign-file.c in the linux kernel ++ * source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible. ++ */ ++struct module_signature ++{ ++ grub_uint8_t algo; /* Public-key crypto algorithm [0] */ ++ grub_uint8_t hash; /* Digest algorithm [0] */ ++ grub_uint8_t id_type; /* Key identifier type [PKEY_ID_PKCS7] */ ++ grub_uint8_t signer_len; /* Length of signer's name [0] */ ++ grub_uint8_t key_id_len; /* Length of key identifier [0] */ ++ grub_uint8_t __pad[3]; ++ grub_uint32_t sig_len; /* Length of signature data */ ++} GRUB_PACKED; ++ ++ ++/* This represents an entire, parsed, appended signature */ ++struct grub_appended_signature ++{ ++ grub_size_t signature_len; /* Length of PKCS#7 data + ++ * metadata + magic */ ++ ++ struct module_signature sig_metadata; /* Module signature metadata */ ++ struct pkcs7_signedData pkcs7; /* Parsed PKCS#7 data */ ++}; ++ ++/* Trusted certificates for verifying appended signatures */ ++struct x509_certificate *grub_trusted_key; ++ ++/* ++ * Force gcry_rsa to be a module dependency. ++ * ++ * If we use grub_crypto_pk_rsa, then then the gcry_rsa module won't be built ++ * in if you add 'appendedsig' to grub-install --modules. You would need to ++ * add 'gcry_rsa' too. That's confusing and seems suboptimal, especially when ++ * we only support RSA. ++ * ++ * Dynamic loading also causes some concerns. We can't load gcry_rsa from the ++ * the filesystem after we install the verifier - we won't be able to verify ++ * it without having it already present. We also shouldn't load it before we ++ * install the verifier, because that would mean it wouldn't be verified - an ++ * attacker could insert any code they wanted into the module. ++ * ++ * So instead, reference the internal symbol from gcry_rsa. That creates a ++ * direct dependency on gcry_rsa, so it will be built in when this module ++ * is built in. Being built in (assuming the core image is itself signed!) ++ * also resolves our concerns about loading from the filesystem. ++ */ ++extern gcry_pk_spec_t _gcry_pubkey_spec_rsa; ++ ++static int check_sigs = 0; ++ ++static const char * ++grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ if (check_sigs == 2) ++ return "forced"; ++ else if (check_sigs == 1) ++ return "enforce"; ++ else ++ return "no"; ++} ++ ++static char * ++grub_env_write_sec (struct grub_env_var *var __attribute__((unused)), ++ const char *val) ++{ ++ /* Do not allow the value to be changed if set to forced */ ++ if (check_sigs == 2) ++ return grub_strdup ("forced"); ++ ++ if ((*val == '2') || (*val == 'f')) ++ check_sigs = 2; ++ else if ((*val == '1') || (*val == 'e')) ++ check_sigs = 1; ++ else if ((*val == '0') || (*val == 'n')) ++ check_sigs = 0; ++ ++ return grub_strdup (grub_env_read_sec (NULL, NULL)); ++} ++ ++static grub_err_t ++read_cert_from_file (grub_file_t f, struct x509_certificate *certificate) ++{ ++ grub_err_t err; ++ grub_uint8_t *buf = NULL; ++ grub_ssize_t read_size; ++ grub_off_t total_read_size = 0; ++ grub_off_t file_size = grub_file_size (f); ++ ++ ++ if (file_size == GRUB_FILE_SIZE_UNKNOWN) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Cannot parse a certificate file of unknown size")); ++ ++ buf = grub_zalloc (file_size); ++ if (!buf) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("Could not allocate buffer for certificate file contents")); ++ ++ while (total_read_size < file_size) ++ { ++ read_size = ++ grub_file_read (f, &buf[total_read_size], ++ file_size - total_read_size); ++ if (read_size < 0) ++ { ++ err = grub_error (GRUB_ERR_READ_ERROR, ++ N_("Error reading certificate file")); ++ goto cleanup_buf; ++ } ++ total_read_size += read_size; ++ } ++ ++ err = certificate_import (buf, total_read_size, certificate); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup_buf; ++ ++ return GRUB_ERR_NONE; ++ ++cleanup_buf: ++ grub_free (buf); ++ return err; ++} ++ ++static grub_err_t ++extract_appended_signature (grub_uint8_t * buf, grub_size_t bufsize, ++ struct grub_appended_signature *sig) ++{ ++ grub_err_t err; ++ grub_size_t pkcs7_size; ++ grub_size_t remaining_len; ++ grub_uint8_t *appsigdata = buf + bufsize - grub_strlen (magic); ++ ++ if (bufsize < grub_strlen (magic)) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("File too short for signature magic")); ++ ++ if (grub_memcmp (appsigdata, (grub_uint8_t *) magic, grub_strlen (magic))) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("Missing or invalid signature magic")); ++ ++ remaining_len = bufsize - grub_strlen (magic); ++ ++ if (remaining_len < sizeof (struct module_signature)) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("File too short for signature metadata")); ++ ++ appsigdata -= sizeof (struct module_signature); ++ ++ /* extract the metadata */ ++ grub_memcpy (&(sig->sig_metadata), appsigdata, ++ sizeof (struct module_signature)); ++ ++ remaining_len -= sizeof (struct module_signature); ++ ++ if (sig->sig_metadata.id_type != 2) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Wrong signature type")); ++ ++#ifdef GRUB_TARGET_WORDS_BIGENDIAN ++ pkcs7_size = sig->sig_metadata.sig_len; ++#else ++ pkcs7_size = __builtin_bswap32 (sig->sig_metadata.sig_len); ++#endif ++ ++ if (pkcs7_size > remaining_len) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("File too short for PKCS#7 message")); ++ ++ grub_dprintf ("appendedsig", "sig len %" PRIuGRUB_SIZE "\n", pkcs7_size); ++ ++ sig->signature_len = ++ grub_strlen (magic) + sizeof (struct module_signature) + pkcs7_size; ++ ++ /* rewind pointer and parse pkcs7 data */ ++ appsigdata -= pkcs7_size; ++ ++ err = parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_verify_appended_signature (grub_uint8_t * buf, grub_size_t bufsize) ++{ ++ grub_err_t err = GRUB_ERR_NONE; ++ grub_size_t datasize; ++ void *context; ++ unsigned char *hash; ++ gcry_mpi_t hashmpi; ++ gcry_err_code_t rc; ++ struct x509_certificate *pk; ++ struct grub_appended_signature sig; ++ ++ if (!grub_trusted_key) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("No trusted keys to verify against")); ++ ++ err = extract_appended_signature (buf, bufsize, &sig); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ datasize = bufsize - sig.signature_len; ++ ++ context = grub_zalloc (sig.pkcs7.hash->contextsize); ++ if (!context) ++ return grub_errno; ++ ++ sig.pkcs7.hash->init (context); ++ sig.pkcs7.hash->write (context, buf, datasize); ++ sig.pkcs7.hash->final (context); ++ hash = sig.pkcs7.hash->read (context); ++ grub_dprintf ("appendedsig", ++ "data size %" PRIxGRUB_SIZE ", hash %02x%02x%02x%02x...\n", ++ datasize, hash[0], hash[1], hash[2], hash[3]); ++ ++ err = GRUB_ERR_BAD_SIGNATURE; ++ for (pk = grub_trusted_key; pk; pk = pk->next) ++ { ++ rc = grub_crypto_rsa_pad (&hashmpi, hash, sig.pkcs7.hash, pk->mpis[0]); ++ if (rc) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("Error padding hash for RSA verification: %d"), ++ rc); ++ goto cleanup; ++ } ++ ++ rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &sig.pkcs7.sig_mpi, ++ pk->mpis, NULL, NULL); ++ gcry_mpi_release (hashmpi); ++ ++ if (rc == 0) ++ { ++ grub_dprintf ("appendedsig", "verify with key '%s' succeeded\n", ++ pk->subject); ++ err = GRUB_ERR_NONE; ++ break; ++ } ++ ++ grub_dprintf ("appendedsig", "verify with key '%s' failed with %d\n", ++ pk->subject, rc); ++ } ++ ++ /* If we didn't verify, provide a neat message */ ++ if (err != GRUB_ERR_NONE) ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("Failed to verify signature against a trusted key")); ++ ++cleanup: ++ grub_free (context); ++ pkcs7_signedData_release (&sig.pkcs7); ++ ++ return err; ++} ++ ++static grub_err_t ++grub_cmd_verify_signature (grub_command_t cmd __attribute__((unused)), ++ int argc, char **args) ++{ ++ grub_file_t f; ++ grub_err_t err = GRUB_ERR_NONE; ++ grub_uint8_t *data; ++ grub_ssize_t read_size; ++ grub_off_t file_size, total_read_size = 0; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); ++ ++ grub_dprintf ("appendedsig", "verifying %s\n", args[0]); ++ ++ f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE); ++ if (!f) ++ { ++ err = grub_errno; ++ goto cleanup; ++ } ++ ++ file_size = grub_file_size (f); ++ if (file_size == GRUB_FILE_SIZE_UNKNOWN) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Cannot verify the signature of a file of unknown size")); ++ ++ data = grub_malloc (file_size); ++ if (!data) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("Could not allocate data buffer size %" ++ PRIuGRUB_UINT64_T " for verification"), file_size); ++ ++ while (total_read_size < file_size) ++ { ++ read_size = ++ grub_file_read (f, &data[total_read_size], ++ file_size - total_read_size); ++ if (read_size < 0) ++ { ++ err = grub_error (GRUB_ERR_READ_ERROR, ++ N_("Error reading file to verify")); ++ goto cleanup_data; ++ } ++ total_read_size += read_size; ++ } ++ ++ err = grub_verify_appended_signature (data, file_size); ++ ++cleanup_data: ++ grub_free (data); ++cleanup: ++ if (f) ++ grub_file_close (f); ++ return err; ++} ++ ++static grub_err_t ++grub_cmd_distrust (grub_command_t cmd __attribute__((unused)), ++ int argc, char **args) ++{ ++ unsigned long cert_num, i; ++ struct x509_certificate *cert, *prev; ++ ++ if (argc != 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("One argument expected")); ++ ++ grub_errno = GRUB_ERR_NONE; ++ cert_num = grub_strtoul (args[0], NULL, 10); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ if (cert_num < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Certificate number too small - numbers start at 1")); ++ ++ if (cert_num == 1) ++ { ++ cert = grub_trusted_key; ++ grub_trusted_key = cert->next; ++ ++ certificate_release (cert); ++ grub_free (cert); ++ return GRUB_ERR_NONE; ++ } ++ i = 2; ++ prev = grub_trusted_key; ++ cert = grub_trusted_key->next; ++ while (cert) ++ { ++ if (i == cert_num) ++ { ++ prev->next = cert->next; ++ certificate_release (cert); ++ grub_free (cert); ++ return GRUB_ERR_NONE; ++ } ++ i++; ++ prev = cert; ++ cert = cert->next; ++ } ++ ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("No certificate number %lu found - only %lu certificates in the store"), ++ cert_num, i - 1); ++} ++ ++static grub_err_t ++grub_cmd_trust (grub_command_t cmd __attribute__((unused)), ++ int argc, char **args) ++{ ++ grub_file_t certf; ++ struct x509_certificate *cert = NULL; ++ grub_err_t err; ++ ++ if (argc != 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); ++ ++ certf = grub_file_open (args[0], ++ GRUB_FILE_TYPE_CERTIFICATE_TRUST ++ | GRUB_FILE_TYPE_NO_DECOMPRESS); ++ if (!certf) ++ return grub_errno; ++ ++ ++ cert = grub_zalloc (sizeof (struct x509_certificate)); ++ if (!cert) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("Could not allocate memory for certificate")); ++ ++ err = read_cert_from_file (certf, cert); ++ grub_file_close (certf); ++ if (err != GRUB_ERR_NONE) ++ { ++ grub_free (cert); ++ return err; ++ } ++ grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n", ++ cert->subject); ++ ++ cert->next = grub_trusted_key; ++ grub_trusted_key = cert; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_list (grub_command_t cmd __attribute__((unused)), ++ int argc __attribute__((unused)), ++ char **args __attribute__((unused))) ++{ ++ struct x509_certificate *cert; ++ int cert_num = 1; ++ grub_size_t i; ++ ++ for (cert = grub_trusted_key; cert; cert = cert->next) ++ { ++ grub_printf (N_("Certificate %d:\n"), cert_num); ++ ++ grub_printf (N_("\tSerial: ")); ++ for (i = 0; i < cert->serial_len - 1; i++) ++ { ++ grub_printf ("%02x:", cert->serial[i]); ++ } ++ grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]); ++ ++ grub_printf ("\tCN: %s\n\n", cert->subject); ++ cert_num++; ++ ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++appendedsig_init (grub_file_t io __attribute__((unused)), ++ enum grub_file_type type, ++ void **context __attribute__((unused)), ++ enum grub_verify_flags *flags) ++{ ++ if (!check_sigs) ++ { ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ return GRUB_ERR_NONE; ++ } ++ ++ switch (type & GRUB_FILE_TYPE_MASK) ++ { ++ case GRUB_FILE_TYPE_CERTIFICATE_TRUST: ++ /* ++ * This is a certificate to add to trusted keychain. ++ * ++ * This needs to be verified or blocked. Ideally we'd write an x509 ++ * verifier, but we lack the hubris required to take this on. Instead, ++ * require that it have an appended signature. ++ */ ++ ++ /* Fall through */ ++ ++ case GRUB_FILE_TYPE_LINUX_KERNEL: ++ case GRUB_FILE_TYPE_GRUB_MODULE: ++ /* ++ * Appended signatures are only defined for ELF binaries. ++ * Out of an abundance of caution, we only verify Linux kernels and ++ * GRUB modules at this point. ++ */ ++ *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; ++ return GRUB_ERR_NONE; ++ ++ case GRUB_FILE_TYPE_ACPI_TABLE: ++ case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: ++ /* ++ * It is possible to use appended signature verification without ++ * lockdown - like the PGP verifier. When combined with an embedded ++ * config file in a signed grub binary, this could still be a meaningful ++ * secure-boot chain - so long as it isn't subverted by something like a ++ * rouge ACPI table or DT image. Defer them explicitly. ++ */ ++ *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; ++ return GRUB_ERR_NONE; ++ ++ default: ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ return GRUB_ERR_NONE; ++ } ++} ++ ++static grub_err_t ++appendedsig_write (void *ctxt __attribute__((unused)), ++ void *buf, grub_size_t size) ++{ ++ return grub_verify_appended_signature (buf, size); ++} ++ ++struct grub_file_verifier grub_appendedsig_verifier = { ++ .name = "appendedsig", ++ .init = appendedsig_init, ++ .write = appendedsig_write, ++}; ++ ++static grub_ssize_t ++pseudo_read (struct grub_file *file, char *buf, grub_size_t len) ++{ ++ grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len); ++ return len; ++} ++ ++/* Filesystem descriptor. */ ++static struct grub_fs pseudo_fs = { ++ .name = "pseudo", ++ .fs_read = pseudo_read ++}; ++ ++static grub_command_t cmd_verify, cmd_list, cmd_distrust, cmd_trust; ++ ++GRUB_MOD_INIT (appendedsig) ++{ ++ int rc; ++ struct grub_module_header *header; ++ ++ /* If in lockdown, immediately enter forced mode */ ++ if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED) ++ check_sigs = 2; ++ ++ grub_trusted_key = NULL; ++ ++ grub_register_variable_hook ("check_appended_signatures", ++ grub_env_read_sec, ++ grub_env_write_sec); ++ grub_env_export ("check_appended_signatures"); ++ ++ rc = asn1_init (); ++ if (rc) ++ grub_fatal ("Error initing ASN.1 data structures: %d: %s\n", rc, ++ asn1_strerror (rc)); ++ ++ FOR_MODULES (header) ++ { ++ struct grub_file pseudo_file; ++ struct x509_certificate *pk = NULL; ++ grub_err_t err; ++ ++ /* Not an ELF module, skip. */ ++ if (header->type != OBJ_TYPE_X509_PUBKEY) ++ continue; ++ ++ grub_memset (&pseudo_file, 0, sizeof (pseudo_file)); ++ pseudo_file.fs = &pseudo_fs; ++ pseudo_file.size = header->size - sizeof (struct grub_module_header); ++ pseudo_file.data = (char *) header + sizeof (struct grub_module_header); ++ ++ grub_dprintf ("appendedsig", ++ "Found an x509 key, size=%" PRIuGRUB_UINT64_T "\n", ++ pseudo_file.size); ++ ++ pk = grub_zalloc (sizeof (struct x509_certificate)); ++ if (!pk) ++ { ++ grub_fatal ("Out of memory loading initial certificates"); ++ } ++ ++ err = read_cert_from_file (&pseudo_file, pk); ++ if (err != GRUB_ERR_NONE) ++ grub_fatal ("Error loading initial key: %s", grub_errmsg); ++ ++ grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", pk->subject); ++ ++ pk->next = grub_trusted_key; ++ grub_trusted_key = pk; ++ } ++ ++ cmd_trust = ++ grub_register_command ("trust_certificate", grub_cmd_trust, ++ N_("X509_CERTIFICATE"), ++ N_("Add X509_CERTIFICATE to trusted certificates.")); ++ cmd_list = ++ grub_register_command ("list_certificates", grub_cmd_list, 0, ++ N_("Show the list of trusted x509 certificates.")); ++ cmd_verify = ++ grub_register_command ("verify_appended", grub_cmd_verify_signature, ++ N_("FILE"), ++ N_("Verify FILE against the trusted x509 certificates.")); ++ cmd_distrust = ++ grub_register_command ("distrust_certificate", grub_cmd_distrust, ++ N_("CERT_NUMBER"), ++ N_("Remove CERT_NUMBER (as listed by list_certificates) from trusted certificates.")); ++ ++ grub_verifier_register (&grub_appendedsig_verifier); ++ grub_dl_set_persistent (mod); ++} ++ ++GRUB_MOD_FINI (appendedsig) ++{ ++ /* ++ * grub_dl_set_persistent should prevent this from actually running, but ++ * it does still run under emu. ++ */ ++ ++ grub_verifier_unregister (&grub_appendedsig_verifier); ++ grub_unregister_command (cmd_verify); ++ grub_unregister_command (cmd_list); ++ grub_unregister_command (cmd_trust); ++ grub_unregister_command (cmd_distrust); ++} +diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h +new file mode 100644 +index 000000000..9792ef390 +--- /dev/null ++++ b/grub-core/commands/appendedsig/appendedsig.h +@@ -0,0 +1,110 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++ ++extern asn1_node _gnutls_gnutls_asn; ++extern asn1_node _gnutls_pkix_asn; ++ ++#define MAX_OID_LEN 32 ++ ++/* ++ * One or more x509 certificates. ++ * ++ * We do limited parsing: extracting only the serial, CN and RSA public key. ++ */ ++struct x509_certificate ++{ ++ struct x509_certificate *next; ++ ++ grub_uint8_t *serial; ++ grub_size_t serial_len; ++ ++ char *subject; ++ grub_size_t subject_len; ++ ++ /* We only support RSA public keys. This encodes [modulus, publicExponent] */ ++ gcry_mpi_t mpis[2]; ++}; ++ ++/* ++ * A PKCS#7 signedData message. ++ * ++ * We make no attempt to match intelligently, so we don't save any info about ++ * the signer. We also support only 1 signerInfo, so we only store a single ++ * MPI for the signature. ++ */ ++struct pkcs7_signedData ++{ ++ const gcry_md_spec_t *hash; ++ gcry_mpi_t sig_mpi; ++}; ++ ++ ++/* Do libtasn1 init */ ++int asn1_init (void); ++ ++/* ++ * Import a DER-encoded certificate at 'data', of size 'size'. ++ * ++ * Place the results into 'results', which must be already allocated. ++ */ ++grub_err_t ++certificate_import (void *data, grub_size_t size, ++ struct x509_certificate *results); ++ ++/* ++ * Release all the storage associated with the x509 certificate. ++ * If the caller dynamically allocated the certificate, it must free it. ++ * The caller is also responsible for maintenance of the linked list. ++ */ ++void certificate_release (struct x509_certificate *cert); ++ ++/* ++ * Parse a PKCS#7 message, which must be a signedData message. ++ * ++ * The message must be in 'sigbuf' and of size 'data_size'. The result is ++ * placed in 'msg', which must already be allocated. ++ */ ++grub_err_t ++parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size, ++ struct pkcs7_signedData *msg); ++ ++/* ++ * Release all the storage associated with the PKCS#7 message. ++ * If the caller dynamically allocated the message, it must free it. ++ */ ++void pkcs7_signedData_release (struct pkcs7_signedData *msg); ++ ++/* ++ * Read a value from an ASN1 node, allocating memory to store it. ++ * ++ * It will work for anything where the size libtasn1 returns is right: ++ * - Integers ++ * - Octet strings ++ * - DER encoding of other structures ++ * It will _not_ work for things where libtasn1 size requires adjustment: ++ * - Strings that require an extra NULL byte at the end ++ * - Bit strings because libtasn1 returns the length in bits, not bytes. ++ * ++ * If the function returns a non-NULL value, the caller must free it. ++ */ ++void *grub_asn1_allocate_and_read (asn1_node node, const char *name, ++ const char *friendly_name, ++ int *content_size); +diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c +new file mode 100644 +index 000000000..eff095a9d +--- /dev/null ++++ b/grub-core/commands/appendedsig/asn1util.c +@@ -0,0 +1,102 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "appendedsig.h" ++ ++asn1_node _gnutls_gnutls_asn = ASN1_TYPE_EMPTY; ++asn1_node _gnutls_pkix_asn = ASN1_TYPE_EMPTY; ++ ++extern const ASN1_ARRAY_TYPE gnutls_asn1_tab[]; ++extern const ASN1_ARRAY_TYPE pkix_asn1_tab[]; ++ ++/* ++ * Read a value from an ASN1 node, allocating memory to store it. ++ * ++ * It will work for anything where the size libtasn1 returns is right: ++ * - Integers ++ * - Octet strings ++ * - DER encoding of other structures ++ * It will _not_ work for things where libtasn1 size requires adjustment: ++ * - Strings that require an extra NULL byte at the end ++ * - Bit strings because libtasn1 returns the length in bits, not bytes. ++ * ++ * If the function returns a non-NULL value, the caller must free it. ++ */ ++void * ++grub_asn1_allocate_and_read (asn1_node node, const char *name, ++ const char *friendly_name, int *content_size) ++{ ++ int result; ++ grub_uint8_t *tmpstr = NULL; ++ int tmpstr_size = 0; ++ ++ result = asn1_read_value (node, name, NULL, &tmpstr_size); ++ if (result != ASN1_MEM_ERROR) ++ { ++ grub_snprintf (grub_errmsg, sizeof (grub_errmsg), ++ _ ++ ("Reading size of %s did not return expected status: %s"), ++ friendly_name, asn1_strerror (result)); ++ grub_errno = GRUB_ERR_BAD_FILE_TYPE; ++ return NULL; ++ } ++ ++ tmpstr = grub_malloc (tmpstr_size); ++ if (tmpstr == NULL) ++ { ++ grub_snprintf (grub_errmsg, sizeof (grub_errmsg), ++ "Could not allocate memory to store %s", friendly_name); ++ grub_errno = GRUB_ERR_OUT_OF_MEMORY; ++ return NULL; ++ } ++ ++ result = asn1_read_value (node, name, tmpstr, &tmpstr_size); ++ if (result != ASN1_SUCCESS) ++ { ++ grub_free (tmpstr); ++ grub_snprintf (grub_errmsg, sizeof (grub_errmsg), ++ "Error reading %s: %s", ++ friendly_name, asn1_strerror (result)); ++ grub_errno = GRUB_ERR_BAD_FILE_TYPE; ++ return NULL; ++ } ++ ++ *content_size = tmpstr_size; ++ ++ return tmpstr; ++} ++ ++int ++asn1_init (void) ++{ ++ int res; ++ res = asn1_array2tree (gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL); ++ if (res != ASN1_SUCCESS) ++ { ++ return res; ++ } ++ res = asn1_array2tree (pkix_asn1_tab, &_gnutls_pkix_asn, NULL); ++ return res; ++} +diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c b/grub-core/commands/appendedsig/gnutls_asn1_tab.c +new file mode 100644 +index 000000000..ddd1314e6 +--- /dev/null ++++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c +@@ -0,0 +1,121 @@ ++#include ++#include ++ ++const asn1_static_node gnutls_asn1_tab[] = { ++ { "GNUTLS", 536872976, NULL }, ++ { NULL, 1073741836, NULL }, ++ { "RSAPublicKey", 1610612741, NULL }, ++ { "modulus", 1073741827, NULL }, ++ { "publicExponent", 3, NULL }, ++ { "RSAPrivateKey", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "modulus", 1073741827, NULL }, ++ { "publicExponent", 1073741827, NULL }, ++ { "privateExponent", 1073741827, NULL }, ++ { "prime1", 1073741827, NULL }, ++ { "prime2", 1073741827, NULL }, ++ { "exponent1", 1073741827, NULL }, ++ { "exponent2", 1073741827, NULL }, ++ { "coefficient", 1073741827, NULL }, ++ { "otherPrimeInfos", 16386, "OtherPrimeInfos"}, ++ { "ProvableSeed", 1610612741, NULL }, ++ { "algorithm", 1073741836, NULL }, ++ { "seed", 7, NULL }, ++ { "OtherPrimeInfos", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "OtherPrimeInfo"}, ++ { "OtherPrimeInfo", 1610612741, NULL }, ++ { "prime", 1073741827, NULL }, ++ { "exponent", 1073741827, NULL }, ++ { "coefficient", 3, NULL }, ++ { "AlgorithmIdentifier", 1610612741, NULL }, ++ { "algorithm", 1073741836, NULL }, ++ { "parameters", 541081613, NULL }, ++ { "algorithm", 1, NULL }, ++ { "DigestInfo", 1610612741, NULL }, ++ { "digestAlgorithm", 1073741826, "DigestAlgorithmIdentifier"}, ++ { "digest", 7, NULL }, ++ { "DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"}, ++ { "DSAPublicKey", 1073741827, NULL }, ++ { "DSAParameters", 1610612741, NULL }, ++ { "p", 1073741827, NULL }, ++ { "q", 1073741827, NULL }, ++ { "g", 3, NULL }, ++ { "DSASignatureValue", 1610612741, NULL }, ++ { "r", 1073741827, NULL }, ++ { "s", 3, NULL }, ++ { "DSAPrivateKey", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "p", 1073741827, NULL }, ++ { "q", 1073741827, NULL }, ++ { "g", 1073741827, NULL }, ++ { "Y", 1073741827, NULL }, ++ { "priv", 3, NULL }, ++ { "DHParameter", 1610612741, NULL }, ++ { "prime", 1073741827, NULL }, ++ { "base", 1073741827, NULL }, ++ { "privateValueLength", 16387, NULL }, ++ { "ECParameters", 1610612754, NULL }, ++ { "namedCurve", 12, NULL }, ++ { "ECPrivateKey", 1610612741, NULL }, ++ { "Version", 1073741827, NULL }, ++ { "privateKey", 1073741831, NULL }, ++ { "parameters", 1610637314, "ECParameters"}, ++ { NULL, 2056, "0"}, ++ { "publicKey", 536895494, NULL }, ++ { NULL, 2056, "1"}, ++ { "PrincipalName", 1610612741, NULL }, ++ { "name-type", 1610620931, NULL }, ++ { NULL, 2056, "0"}, ++ { "name-string", 536879115, NULL }, ++ { NULL, 1073743880, "1"}, ++ { NULL, 27, NULL }, ++ { "KRB5PrincipalName", 1610612741, NULL }, ++ { "realm", 1610620955, NULL }, ++ { NULL, 2056, "0"}, ++ { "principalName", 536879106, "PrincipalName"}, ++ { NULL, 2056, "1"}, ++ { "RSAPSSParameters", 1610612741, NULL }, ++ { "hashAlgorithm", 1610637314, "AlgorithmIdentifier"}, ++ { NULL, 2056, "0"}, ++ { "maskGenAlgorithm", 1610637314, "AlgorithmIdentifier"}, ++ { NULL, 2056, "1"}, ++ { "saltLength", 1610653699, NULL }, ++ { NULL, 1073741833, "20"}, ++ { NULL, 2056, "2"}, ++ { "trailerField", 536911875, NULL }, ++ { NULL, 1073741833, "1"}, ++ { NULL, 2056, "3"}, ++ { "GOSTParameters", 1610612741, NULL }, ++ { "publicKeyParamSet", 1073741836, NULL }, ++ { "digestParamSet", 16396, NULL }, ++ { "GOSTParametersOld", 1610612741, NULL }, ++ { "publicKeyParamSet", 1073741836, NULL }, ++ { "digestParamSet", 1073741836, NULL }, ++ { "encryptionParamSet", 16396, NULL }, ++ { "GOSTPrivateKey", 1073741831, NULL }, ++ { "GOSTPrivateKeyOld", 1073741827, NULL }, ++ { "IssuerSignTool", 1610612741, NULL }, ++ { "signTool", 1073741858, NULL }, ++ { "cATool", 1073741858, NULL }, ++ { "signToolCert", 1073741858, NULL }, ++ { "cAToolCert", 34, NULL }, ++ { "Gost28147-89-EncryptedKey", 1610612741, NULL }, ++ { "encryptedKey", 1073741831, NULL }, ++ { "maskKey", 1610637319, NULL }, ++ { NULL, 4104, "0"}, ++ { "macKey", 7, NULL }, ++ { "SubjectPublicKeyInfo", 1610612741, NULL }, ++ { "algorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "subjectPublicKey", 6, NULL }, ++ { "GostR3410-TransportParameters", 1610612741, NULL }, ++ { "encryptionParamSet", 1073741836, NULL }, ++ { "ephemeralPublicKey", 1610637314, "SubjectPublicKeyInfo"}, ++ { NULL, 4104, "0"}, ++ { "ukm", 7, NULL }, ++ { "GostR3410-KeyTransport", 536870917, NULL }, ++ { "sessionEncryptedKey", 1073741826, "Gost28147-89-EncryptedKey"}, ++ { "transportParameters", 536895490, "GostR3410-TransportParameters"}, ++ { NULL, 4104, "0"}, ++ { NULL, 0, NULL } ++}; +diff --git a/grub-core/commands/appendedsig/pkcs7.c b/grub-core/commands/appendedsig/pkcs7.c +new file mode 100644 +index 000000000..dc6afe203 +--- /dev/null ++++ b/grub-core/commands/appendedsig/pkcs7.c +@@ -0,0 +1,305 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include "appendedsig.h" ++#include ++#include ++#include ++ ++ ++static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ ++/* ++ * RFC 5652 s 5.1 ++ */ ++const char *signedData_oid = "1.2.840.113549.1.7.2"; ++ ++/* ++ * RFC 4055 s 2.1 ++ */ ++const char *sha256_oid = "2.16.840.1.101.3.4.2.1"; ++const char *sha512_oid = "2.16.840.1.101.3.4.2.3"; ++ ++static grub_err_t ++process_content (grub_uint8_t * content, int size, ++ struct pkcs7_signedData *msg) ++{ ++ int res; ++ asn1_node signed_part; ++ grub_err_t err = GRUB_ERR_NONE; ++ char algo_oid[MAX_OID_LEN]; ++ int algo_oid_size = sizeof (algo_oid); ++ int algo_count; ++ char version; ++ int version_size = sizeof (version); ++ grub_uint8_t *result_buf; ++ int result_size = 0; ++ int crls_size = 0; ++ gcry_error_t gcry_err; ++ ++ res = asn1_create_element (_gnutls_pkix_asn, "PKIX1.pkcs-7-SignedData", ++ &signed_part); ++ if (res != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for PKCS#7 signed part."); ++ } ++ ++ res = asn1_der_decoding2 (&signed_part, content, &size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading PKCS#7 signed data: %s", asn1_error); ++ goto cleanup_signed_part; ++ } ++ ++ /* SignedData ::= SEQUENCE { ++ * version CMSVersion, ++ * digestAlgorithms DigestAlgorithmIdentifiers, ++ * encapContentInfo EncapsulatedContentInfo, ++ * certificates [0] IMPLICIT CertificateSet OPTIONAL, ++ * crls [1] IMPLICIT RevocationInfoChoices OPTIONAL, ++ * signerInfos SignerInfos } ++ */ ++ ++ /* version per the algo in 5.1, must be 1 */ ++ res = asn1_read_value (signed_part, "version", &version, &version_size); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading signedData version: %s", ++ asn1_strerror (res)); ++ goto cleanup_signed_part; ++ } ++ ++ if (version != 1) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Unexpected signature version v%d, only v1 supported", ++ version); ++ goto cleanup_signed_part; ++ } ++ ++ /* ++ * digestAlgorithms DigestAlgorithmIdentifiers ++ * ++ * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier ++ * DigestAlgorithmIdentifer is an X.509 AlgorithmIdentifier (10.1.1) ++ * ++ * RFC 4055 s 2.1: ++ * sha256Identifier AlgorithmIdentifier ::= { id-sha256, NULL } ++ * sha512Identifier AlgorithmIdentifier ::= { id-sha512, NULL } ++ * ++ * We only support 1 element in the set, and we do not check parameters atm. ++ */ ++ res = ++ asn1_number_of_elements (signed_part, "digestAlgorithms", &algo_count); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error counting number of digest algorithms: %s", ++ asn1_strerror (res)); ++ goto cleanup_signed_part; ++ } ++ ++ if (algo_count != 1) ++ { ++ err = ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Only 1 digest algorithm is supported"); ++ goto cleanup_signed_part; ++ } ++ ++ res = ++ asn1_read_value (signed_part, "digestAlgorithms.?1.algorithm", algo_oid, ++ &algo_oid_size); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading digest algorithm: %s", ++ asn1_strerror (res)); ++ goto cleanup_signed_part; ++ } ++ ++ if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0) ++ { ++ msg->hash = grub_crypto_lookup_md_by_name ("sha512"); ++ } ++ else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0) ++ { ++ msg->hash = grub_crypto_lookup_md_by_name ("sha256"); ++ } ++ else ++ { ++ err = ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Only SHA-256 and SHA-512 hashes are supported, found OID %s", ++ algo_oid); ++ goto cleanup_signed_part; ++ } ++ ++ if (!msg->hash) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Hash algorithm for OID %s not loaded", algo_oid); ++ goto cleanup_signed_part; ++ } ++ ++ /* ++ * We ignore the certificates, but we don't permit CRLs. ++ * A CRL entry might be revoking the certificate we're using, and we have ++ * no way of dealing with that at the moment. ++ */ ++ res = asn1_read_value (signed_part, "crls", NULL, &crls_size); ++ if (res != ASN1_ELEMENT_NOT_FOUND) ++ { ++ err = ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "PKCS#7 messages with embedded CRLs are not supported"); ++ goto cleanup_signed_part; ++ } ++ ++ /* read the signature */ ++ result_buf = ++ grub_asn1_allocate_and_read (signed_part, "signerInfos.?1.signature", ++ "signature data", &result_size); ++ if (!result_buf) ++ { ++ err = grub_errno; ++ goto cleanup_signed_part; ++ } ++ ++ gcry_err = ++ gcry_mpi_scan (&(msg->sig_mpi), GCRYMPI_FMT_USG, result_buf, result_size, ++ NULL); ++ if (gcry_err != GPG_ERR_NO_ERROR) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error loading signature into MPI structure: %d", ++ gcry_err); ++ goto cleanup_result; ++ } ++ ++cleanup_result: ++ grub_free (result_buf); ++cleanup_signed_part: ++ asn1_delete_structure (&signed_part); ++ ++ return err; ++} ++ ++grub_err_t ++parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size, ++ struct pkcs7_signedData *msg) ++{ ++ int res; ++ asn1_node content_info; ++ grub_err_t err = GRUB_ERR_NONE; ++ char content_oid[MAX_OID_LEN]; ++ grub_uint8_t *content; ++ int content_size; ++ int content_oid_size = sizeof (content_oid); ++ int size; ++ ++ if (data_size > GRUB_INT_MAX) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ "Cannot parse a PKCS#7 message where data size > INT_MAX"); ++ size = (int) data_size; ++ ++ res = asn1_create_element (_gnutls_pkix_asn, ++ "PKIX1.pkcs-7-ContentInfo", &content_info); ++ if (res != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for PKCS#7 data: %s", ++ asn1_strerror (res)); ++ } ++ ++ res = asn1_der_decoding2 (&content_info, sigbuf, &size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error decoding PKCS#7 message DER: %s", asn1_error); ++ goto cleanup; ++ } ++ ++ /* ++ * ContentInfo ::= SEQUENCE { ++ * contentType ContentType, ++ * content [0] EXPLICIT ANY DEFINED BY contentType } ++ * ++ * ContentType ::= OBJECT IDENTIFIER ++ */ ++ res = ++ asn1_read_value (content_info, "contentType", content_oid, ++ &content_oid_size); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading PKCS#7 content type: %s", ++ asn1_strerror (res)); ++ goto cleanup; ++ } ++ ++ /* OID for SignedData defined in 5.1 */ ++ if (grub_strncmp (signedData_oid, content_oid, content_oid_size) != 0) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Unexpected content type in PKCS#7 message: OID %s", ++ content_oid); ++ goto cleanup; ++ } ++ ++ content = ++ grub_asn1_allocate_and_read (content_info, "content", ++ "PKCS#7 message content", &content_size); ++ if (!content) ++ { ++ err = grub_errno; ++ goto cleanup; ++ } ++ ++ err = process_content (content, content_size, msg); ++ grub_free (content); ++ ++cleanup: ++ asn1_delete_structure (&content_info); ++ return err; ++} ++ ++/* ++ * Release all the storage associated with the PKCS#7 message. ++ * If the caller dynamically allocated the message, it must free it. ++ */ ++void ++pkcs7_signedData_release (struct pkcs7_signedData *msg) ++{ ++ gcry_mpi_release (msg->sig_mpi); ++} +diff --git a/grub-core/commands/appendedsig/pkix_asn1_tab.c b/grub-core/commands/appendedsig/pkix_asn1_tab.c +new file mode 100644 +index 000000000..adef69d95 +--- /dev/null ++++ b/grub-core/commands/appendedsig/pkix_asn1_tab.c +@@ -0,0 +1,484 @@ ++#include ++#include ++ ++const asn1_static_node pkix_asn1_tab[] = { ++ { "PKIX1", 536875024, NULL }, ++ { NULL, 1073741836, NULL }, ++ { "PrivateKeyUsagePeriod", 1610612741, NULL }, ++ { "notBefore", 1610637349, NULL }, ++ { NULL, 4104, "0"}, ++ { "notAfter", 536895525, NULL }, ++ { NULL, 4104, "1"}, ++ { "AuthorityKeyIdentifier", 1610612741, NULL }, ++ { "keyIdentifier", 1610637319, NULL }, ++ { NULL, 4104, "0"}, ++ { "authorityCertIssuer", 1610637314, "GeneralNames"}, ++ { NULL, 4104, "1"}, ++ { "authorityCertSerialNumber", 536895490, "CertificateSerialNumber"}, ++ { NULL, 4104, "2"}, ++ { "SubjectKeyIdentifier", 1073741831, NULL }, ++ { "KeyUsage", 1073741830, NULL }, ++ { "DirectoryString", 1610612754, NULL }, ++ { "teletexString", 1612709918, NULL }, ++ { "MAX", 524298, "1"}, ++ { "printableString", 1612709919, NULL }, ++ { "MAX", 524298, "1"}, ++ { "universalString", 1612709920, NULL }, ++ { "MAX", 524298, "1"}, ++ { "utf8String", 1612709922, NULL }, ++ { "MAX", 524298, "1"}, ++ { "bmpString", 1612709921, NULL }, ++ { "MAX", 524298, "1"}, ++ { "ia5String", 538968093, NULL }, ++ { "MAX", 524298, "1"}, ++ { "SubjectAltName", 1073741826, "GeneralNames"}, ++ { "GeneralNames", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "GeneralName"}, ++ { "GeneralName", 1610612754, NULL }, ++ { "otherName", 1610620930, "AnotherName"}, ++ { NULL, 4104, "0"}, ++ { "rfc822Name", 1610620957, NULL }, ++ { NULL, 4104, "1"}, ++ { "dNSName", 1610620957, NULL }, ++ { NULL, 4104, "2"}, ++ { "x400Address", 1610620941, NULL }, ++ { NULL, 4104, "3"}, ++ { "directoryName", 1610620939, NULL }, ++ { NULL, 1073743880, "4"}, ++ { NULL, 2, "RelativeDistinguishedName"}, ++ { "ediPartyName", 1610620941, NULL }, ++ { NULL, 4104, "5"}, ++ { "uniformResourceIdentifier", 1610620957, NULL }, ++ { NULL, 4104, "6"}, ++ { "iPAddress", 1610620935, NULL }, ++ { NULL, 4104, "7"}, ++ { "registeredID", 536879116, NULL }, ++ { NULL, 4104, "8"}, ++ { "AnotherName", 1610612741, NULL }, ++ { "type-id", 1073741836, NULL }, ++ { "value", 541073421, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "type-id", 1, NULL }, ++ { "IssuerAltName", 1073741826, "GeneralNames"}, ++ { "BasicConstraints", 1610612741, NULL }, ++ { "cA", 1610645508, NULL }, ++ { NULL, 131081, NULL }, ++ { "pathLenConstraint", 537411587, NULL }, ++ { "0", 10, "MAX"}, ++ { "CRLDistributionPoints", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "DistributionPoint"}, ++ { "DistributionPoint", 1610612741, NULL }, ++ { "distributionPoint", 1610637314, "DistributionPointName"}, ++ { NULL, 2056, "0"}, ++ { "reasons", 1610637314, "ReasonFlags"}, ++ { NULL, 4104, "1"}, ++ { "cRLIssuer", 536895490, "GeneralNames"}, ++ { NULL, 4104, "2"}, ++ { "DistributionPointName", 1610612754, NULL }, ++ { "fullName", 1610620930, "GeneralNames"}, ++ { NULL, 4104, "0"}, ++ { "nameRelativeToCRLIssuer", 536879106, "RelativeDistinguishedName"}, ++ { NULL, 4104, "1"}, ++ { "ReasonFlags", 1073741830, NULL }, ++ { "ExtKeyUsageSyntax", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 12, NULL }, ++ { "AuthorityInfoAccessSyntax", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "AccessDescription"}, ++ { "AccessDescription", 1610612741, NULL }, ++ { "accessMethod", 1073741836, NULL }, ++ { "accessLocation", 2, "GeneralName"}, ++ { "Attribute", 1610612741, NULL }, ++ { "type", 1073741836, NULL }, ++ { "values", 536870927, NULL }, ++ { NULL, 13, NULL }, ++ { "AttributeTypeAndValue", 1610612741, NULL }, ++ { "type", 1073741836, NULL }, ++ { "value", 13, NULL }, ++ { "Name", 1610612754, NULL }, ++ { "rdnSequence", 536870923, NULL }, ++ { NULL, 2, "RelativeDistinguishedName"}, ++ { "DistinguishedName", 1610612747, NULL }, ++ { NULL, 2, "RelativeDistinguishedName"}, ++ { "RelativeDistinguishedName", 1612709903, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "AttributeTypeAndValue"}, ++ { "Certificate", 1610612741, NULL }, ++ { "tbsCertificate", 1073741826, "TBSCertificate"}, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 6, NULL }, ++ { "TBSCertificate", 1610612741, NULL }, ++ { "version", 1610653699, NULL }, ++ { NULL, 1073741833, "0"}, ++ { NULL, 2056, "0"}, ++ { "serialNumber", 1073741826, "CertificateSerialNumber"}, ++ { "signature", 1073741826, "AlgorithmIdentifier"}, ++ { "issuer", 1073741826, "Name"}, ++ { "validity", 1073741826, "Validity"}, ++ { "subject", 1073741826, "Name"}, ++ { "subjectPublicKeyInfo", 1073741826, "SubjectPublicKeyInfo"}, ++ { "issuerUniqueID", 1610637314, "UniqueIdentifier"}, ++ { NULL, 4104, "1"}, ++ { "subjectUniqueID", 1610637314, "UniqueIdentifier"}, ++ { NULL, 4104, "2"}, ++ { "extensions", 536895490, "Extensions"}, ++ { NULL, 2056, "3"}, ++ { "CertificateSerialNumber", 1073741827, NULL }, ++ { "Validity", 1610612741, NULL }, ++ { "notBefore", 1073741826, "Time"}, ++ { "notAfter", 2, "Time"}, ++ { "Time", 1610612754, NULL }, ++ { "utcTime", 1073741860, NULL }, ++ { "generalTime", 37, NULL }, ++ { "UniqueIdentifier", 1073741830, NULL }, ++ { "SubjectPublicKeyInfo", 1610612741, NULL }, ++ { "algorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "subjectPublicKey", 6, NULL }, ++ { "Extensions", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "Extension"}, ++ { "Extension", 1610612741, NULL }, ++ { "extnID", 1073741836, NULL }, ++ { "critical", 1610645508, NULL }, ++ { NULL, 131081, NULL }, ++ { "extnValue", 7, NULL }, ++ { "CertificateList", 1610612741, NULL }, ++ { "tbsCertList", 1073741826, "TBSCertList"}, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 6, NULL }, ++ { "TBSCertList", 1610612741, NULL }, ++ { "version", 1073758211, NULL }, ++ { "signature", 1073741826, "AlgorithmIdentifier"}, ++ { "issuer", 1073741826, "Name"}, ++ { "thisUpdate", 1073741826, "Time"}, ++ { "nextUpdate", 1073758210, "Time"}, ++ { "revokedCertificates", 1610629131, NULL }, ++ { NULL, 536870917, NULL }, ++ { "userCertificate", 1073741826, "CertificateSerialNumber"}, ++ { "revocationDate", 1073741826, "Time"}, ++ { "crlEntryExtensions", 16386, "Extensions"}, ++ { "crlExtensions", 536895490, "Extensions"}, ++ { NULL, 2056, "0"}, ++ { "AlgorithmIdentifier", 1610612741, NULL }, ++ { "algorithm", 1073741836, NULL }, ++ { "parameters", 541081613, NULL }, ++ { "algorithm", 1, NULL }, ++ { "Dss-Sig-Value", 1610612741, NULL }, ++ { "r", 1073741827, NULL }, ++ { "s", 3, NULL }, ++ { "Dss-Parms", 1610612741, NULL }, ++ { "p", 1073741827, NULL }, ++ { "q", 1073741827, NULL }, ++ { "g", 3, NULL }, ++ { "pkcs-7-ContentInfo", 1610612741, NULL }, ++ { "contentType", 1073741836, NULL }, ++ { "content", 541073421, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "contentType", 1, NULL }, ++ { "pkcs-7-DigestInfo", 1610612741, NULL }, ++ { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "digest", 7, NULL }, ++ { "pkcs-7-SignedData", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "digestAlgorithms", 1073741826, "pkcs-7-DigestAlgorithmIdentifiers"}, ++ { "encapContentInfo", 1073741826, "pkcs-7-EncapsulatedContentInfo"}, ++ { "certificates", 1610637314, "pkcs-7-CertificateSet"}, ++ { NULL, 4104, "0"}, ++ { "crls", 1610637314, "pkcs-7-CertificateRevocationLists"}, ++ { NULL, 4104, "1"}, ++ { "signerInfos", 2, "pkcs-7-SignerInfos"}, ++ { "pkcs-7-DigestAlgorithmIdentifiers", 1610612751, NULL }, ++ { NULL, 2, "AlgorithmIdentifier"}, ++ { "pkcs-7-EncapsulatedContentInfo", 1610612741, NULL }, ++ { "eContentType", 1073741836, NULL }, ++ { "eContent", 536895501, NULL }, ++ { NULL, 2056, "0"}, ++ { "pkcs-7-CertificateRevocationLists", 1610612751, NULL }, ++ { NULL, 13, NULL }, ++ { "pkcs-7-CertificateChoices", 1610612754, NULL }, ++ { "certificate", 13, NULL }, ++ { "pkcs-7-CertificateSet", 1610612751, NULL }, ++ { NULL, 2, "pkcs-7-CertificateChoices"}, ++ { "IssuerAndSerialNumber", 1610612741, NULL }, ++ { "issuer", 1073741826, "Name"}, ++ { "serialNumber", 2, "CertificateSerialNumber"}, ++ { "pkcs-7-SignerInfo", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "sid", 1073741826, "SignerIdentifier"}, ++ { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signedAttrs", 1610637314, "SignedAttributes"}, ++ { NULL, 4104, "0"}, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 1073741831, NULL }, ++ { "unsignedAttrs", 536895490, "SignedAttributes"}, ++ { NULL, 4104, "1"}, ++ { "SignedAttributes", 1612709903, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "Attribute"}, ++ { "SignerIdentifier", 1610612754, NULL }, ++ { "issuerAndSerialNumber", 1073741826, "IssuerAndSerialNumber"}, ++ { "subjectKeyIdentifier", 536879111, NULL }, ++ { NULL, 4104, "0"}, ++ { "pkcs-7-SignerInfos", 1610612751, NULL }, ++ { NULL, 2, "pkcs-7-SignerInfo"}, ++ { "pkcs-10-CertificationRequestInfo", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "subject", 1073741826, "Name"}, ++ { "subjectPKInfo", 1073741826, "SubjectPublicKeyInfo"}, ++ { "attributes", 536879106, "Attributes"}, ++ { NULL, 4104, "0"}, ++ { "Attributes", 1610612751, NULL }, ++ { NULL, 2, "Attribute"}, ++ { "pkcs-10-CertificationRequest", 1610612741, NULL }, ++ { "certificationRequestInfo", 1073741826, "pkcs-10-CertificationRequestInfo"}, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 6, NULL }, ++ { "pkcs-9-at-challengePassword", 1879048204, NULL }, ++ { "iso", 1073741825, "1"}, ++ { "member-body", 1073741825, "2"}, ++ { "us", 1073741825, "840"}, ++ { "rsadsi", 1073741825, "113549"}, ++ { "pkcs", 1073741825, "1"}, ++ { NULL, 1073741825, "9"}, ++ { NULL, 1, "7"}, ++ { "pkcs-9-challengePassword", 1610612754, NULL }, ++ { "printableString", 1073741855, NULL }, ++ { "utf8String", 34, NULL }, ++ { "pkcs-9-localKeyId", 1073741831, NULL }, ++ { "pkcs-8-PrivateKeyInfo", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "privateKey", 1073741831, NULL }, ++ { "attributes", 536895490, "Attributes"}, ++ { NULL, 4104, "0"}, ++ { "pkcs-8-EncryptedPrivateKeyInfo", 1610612741, NULL }, ++ { "encryptionAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "encryptedData", 2, "pkcs-8-EncryptedData"}, ++ { "pkcs-8-EncryptedData", 1073741831, NULL }, ++ { "pkcs-5-des-CBC-params", 1612709895, NULL }, ++ { NULL, 1048586, "8"}, ++ { "pkcs-5-des-EDE3-CBC-params", 1612709895, NULL }, ++ { NULL, 1048586, "8"}, ++ { "pkcs-5-aes128-CBC-params", 1612709895, NULL }, ++ { NULL, 1048586, "16"}, ++ { "pkcs-5-aes192-CBC-params", 1612709895, NULL }, ++ { NULL, 1048586, "16"}, ++ { "pkcs-5-aes256-CBC-params", 1612709895, NULL }, ++ { NULL, 1048586, "16"}, ++ { "Gost28147-89-Parameters", 1610612741, NULL }, ++ { "iv", 1073741831, NULL }, ++ { "encryptionParamSet", 12, NULL }, ++ { "pkcs-5-PBE-params", 1610612741, NULL }, ++ { "salt", 1073741831, NULL }, ++ { "iterationCount", 3, NULL }, ++ { "pkcs-5-PBES2-params", 1610612741, NULL }, ++ { "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"}, ++ { "encryptionScheme", 2, "AlgorithmIdentifier"}, ++ { "pkcs-5-PBKDF2-params", 1610612741, NULL }, ++ { "salt", 1610612754, NULL }, ++ { "specified", 1073741831, NULL }, ++ { "otherSource", 2, "AlgorithmIdentifier"}, ++ { "iterationCount", 1611137027, NULL }, ++ { "1", 10, "MAX"}, ++ { "keyLength", 1611153411, NULL }, ++ { "1", 10, "MAX"}, ++ { "prf", 16386, "AlgorithmIdentifier"}, ++ { "pkcs-12-PFX", 1610612741, NULL }, ++ { "version", 1610874883, NULL }, ++ { "v3", 1, "3"}, ++ { "authSafe", 1073741826, "pkcs-7-ContentInfo"}, ++ { "macData", 16386, "pkcs-12-MacData"}, ++ { "pkcs-12-PbeParams", 1610612741, NULL }, ++ { "salt", 1073741831, NULL }, ++ { "iterations", 3, NULL }, ++ { "pkcs-12-MacData", 1610612741, NULL }, ++ { "mac", 1073741826, "pkcs-7-DigestInfo"}, ++ { "macSalt", 1073741831, NULL }, ++ { "iterations", 536903683, NULL }, ++ { NULL, 9, "1"}, ++ { "pkcs-12-AuthenticatedSafe", 1610612747, NULL }, ++ { NULL, 2, "pkcs-7-ContentInfo"}, ++ { "pkcs-12-SafeContents", 1610612747, NULL }, ++ { NULL, 2, "pkcs-12-SafeBag"}, ++ { "pkcs-12-SafeBag", 1610612741, NULL }, ++ { "bagId", 1073741836, NULL }, ++ { "bagValue", 1614815245, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "badId", 1, NULL }, ++ { "bagAttributes", 536887311, NULL }, ++ { NULL, 2, "Attribute"}, ++ { "pkcs-12-CertBag", 1610612741, NULL }, ++ { "certId", 1073741836, NULL }, ++ { "certValue", 541073421, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "certId", 1, NULL }, ++ { "pkcs-12-CRLBag", 1610612741, NULL }, ++ { "crlId", 1073741836, NULL }, ++ { "crlValue", 541073421, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "crlId", 1, NULL }, ++ { "pkcs-12-SecretBag", 1610612741, NULL }, ++ { "secretTypeId", 1073741836, NULL }, ++ { "secretValue", 541073421, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "secretTypeId", 1, NULL }, ++ { "pkcs-7-Data", 1073741831, NULL }, ++ { "pkcs-7-EncryptedData", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "encryptedContentInfo", 1073741826, "pkcs-7-EncryptedContentInfo"}, ++ { "unprotectedAttrs", 536895490, "pkcs-7-UnprotectedAttributes"}, ++ { NULL, 4104, "1"}, ++ { "pkcs-7-EncryptedContentInfo", 1610612741, NULL }, ++ { "contentType", 1073741836, NULL }, ++ { "contentEncryptionAlgorithm", 1073741826, "pkcs-7-ContentEncryptionAlgorithmIdentifier"}, ++ { "encryptedContent", 536895495, NULL }, ++ { NULL, 4104, "0"}, ++ { "pkcs-7-ContentEncryptionAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"}, ++ { "pkcs-7-UnprotectedAttributes", 1612709903, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "Attribute"}, ++ { "ProxyCertInfo", 1610612741, NULL }, ++ { "pCPathLenConstraint", 1611153411, NULL }, ++ { "0", 10, "MAX"}, ++ { "proxyPolicy", 2, "ProxyPolicy"}, ++ { "ProxyPolicy", 1610612741, NULL }, ++ { "policyLanguage", 1073741836, NULL }, ++ { "policy", 16391, NULL }, ++ { "certificatePolicies", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "PolicyInformation"}, ++ { "PolicyInformation", 1610612741, NULL }, ++ { "policyIdentifier", 1073741836, NULL }, ++ { "policyQualifiers", 538984459, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "PolicyQualifierInfo"}, ++ { "PolicyQualifierInfo", 1610612741, NULL }, ++ { "policyQualifierId", 1073741836, NULL }, ++ { "qualifier", 541065229, NULL }, ++ { "policyQualifierId", 1, NULL }, ++ { "CPSuri", 1073741853, NULL }, ++ { "UserNotice", 1610612741, NULL }, ++ { "noticeRef", 1073758210, "NoticeReference"}, ++ { "explicitText", 16386, "DisplayText"}, ++ { "NoticeReference", 1610612741, NULL }, ++ { "organization", 1073741826, "DisplayText"}, ++ { "noticeNumbers", 536870923, NULL }, ++ { NULL, 3, NULL }, ++ { "DisplayText", 1610612754, NULL }, ++ { "ia5String", 1612709917, NULL }, ++ { "200", 524298, "1"}, ++ { "visibleString", 1612709923, NULL }, ++ { "200", 524298, "1"}, ++ { "bmpString", 1612709921, NULL }, ++ { "200", 524298, "1"}, ++ { "utf8String", 538968098, NULL }, ++ { "200", 524298, "1"}, ++ { "OCSPRequest", 1610612741, NULL }, ++ { "tbsRequest", 1073741826, "TBSRequest"}, ++ { "optionalSignature", 536895490, "Signature"}, ++ { NULL, 2056, "0"}, ++ { "TBSRequest", 1610612741, NULL }, ++ { "version", 1610653699, NULL }, ++ { NULL, 1073741833, "0"}, ++ { NULL, 2056, "0"}, ++ { "requestorName", 1610637314, "GeneralName"}, ++ { NULL, 2056, "1"}, ++ { "requestList", 1610612747, NULL }, ++ { NULL, 2, "Request"}, ++ { "requestExtensions", 536895490, "Extensions"}, ++ { NULL, 2056, "2"}, ++ { "Signature", 1610612741, NULL }, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 1073741830, NULL }, ++ { "certs", 536895499, NULL }, ++ { NULL, 1073743880, "0"}, ++ { NULL, 2, "Certificate"}, ++ { "Request", 1610612741, NULL }, ++ { "reqCert", 1073741826, "CertID"}, ++ { "singleRequestExtensions", 536895490, "Extensions"}, ++ { NULL, 2056, "0"}, ++ { "CertID", 1610612741, NULL }, ++ { "hashAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "issuerNameHash", 1073741831, NULL }, ++ { "issuerKeyHash", 1073741831, NULL }, ++ { "serialNumber", 2, "CertificateSerialNumber"}, ++ { "OCSPResponse", 1610612741, NULL }, ++ { "responseStatus", 1073741826, "OCSPResponseStatus"}, ++ { "responseBytes", 536895490, "ResponseBytes"}, ++ { NULL, 2056, "0"}, ++ { "OCSPResponseStatus", 1610874901, NULL }, ++ { "successful", 1073741825, "0"}, ++ { "malformedRequest", 1073741825, "1"}, ++ { "internalError", 1073741825, "2"}, ++ { "tryLater", 1073741825, "3"}, ++ { "sigRequired", 1073741825, "5"}, ++ { "unauthorized", 1, "6"}, ++ { "ResponseBytes", 1610612741, NULL }, ++ { "responseType", 1073741836, NULL }, ++ { "response", 7, NULL }, ++ { "BasicOCSPResponse", 1610612741, NULL }, ++ { "tbsResponseData", 1073741826, "ResponseData"}, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 1073741830, NULL }, ++ { "certs", 536895499, NULL }, ++ { NULL, 1073743880, "0"}, ++ { NULL, 2, "Certificate"}, ++ { "ResponseData", 1610612741, NULL }, ++ { "version", 1610653699, NULL }, ++ { NULL, 1073741833, "0"}, ++ { NULL, 2056, "0"}, ++ { "responderID", 1073741826, "ResponderID"}, ++ { "producedAt", 1073741861, NULL }, ++ { "responses", 1610612747, NULL }, ++ { NULL, 2, "SingleResponse"}, ++ { "responseExtensions", 536895490, "Extensions"}, ++ { NULL, 2056, "1"}, ++ { "ResponderID", 1610612754, NULL }, ++ { "byName", 1610620939, NULL }, ++ { NULL, 1073743880, "1"}, ++ { NULL, 2, "RelativeDistinguishedName"}, ++ { "byKey", 536879111, NULL }, ++ { NULL, 2056, "2"}, ++ { "SingleResponse", 1610612741, NULL }, ++ { "certID", 1073741826, "CertID"}, ++ { "certStatus", 1073741826, "CertStatus"}, ++ { "thisUpdate", 1073741861, NULL }, ++ { "nextUpdate", 1610637349, NULL }, ++ { NULL, 2056, "0"}, ++ { "singleExtensions", 536895490, "Extensions"}, ++ { NULL, 2056, "1"}, ++ { "CertStatus", 1610612754, NULL }, ++ { "good", 1610620948, NULL }, ++ { NULL, 4104, "0"}, ++ { "revoked", 1610620930, "RevokedInfo"}, ++ { NULL, 4104, "1"}, ++ { "unknown", 536879106, "UnknownInfo"}, ++ { NULL, 4104, "2"}, ++ { "RevokedInfo", 1610612741, NULL }, ++ { "revocationTime", 1073741861, NULL }, ++ { "revocationReason", 537157653, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "unspecified", 1, "0"}, ++ { "UnknownInfo", 1073741844, NULL }, ++ { "NameConstraints", 1610612741, NULL }, ++ { "permittedSubtrees", 1610637314, "GeneralSubtrees"}, ++ { NULL, 4104, "0"}, ++ { "excludedSubtrees", 536895490, "GeneralSubtrees"}, ++ { NULL, 4104, "1"}, ++ { "GeneralSubtrees", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "GeneralSubtree"}, ++ { "GeneralSubtree", 1610612741, NULL }, ++ { "base", 1073741826, "GeneralName"}, ++ { "minimum", 1610653699, NULL }, ++ { NULL, 1073741833, "0"}, ++ { NULL, 4104, "0"}, ++ { "maximum", 536895491, NULL }, ++ { NULL, 4104, "1"}, ++ { "TlsFeatures", 536870923, NULL }, ++ { NULL, 3, NULL }, ++ { NULL, 0, NULL } ++}; +diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c +new file mode 100644 +index 000000000..42ec65c54 +--- /dev/null ++++ b/grub-core/commands/appendedsig/x509.c +@@ -0,0 +1,1050 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "appendedsig.h" ++ ++static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ ++/* ++ * RFC 3279 2.3.1 RSA Keys ++ */ ++const char *rsaEncryption_oid = "1.2.840.113549.1.1.1"; ++ ++/* ++ * RFC 5280 Appendix A ++ */ ++const char *commonName_oid = "2.5.4.3"; ++ ++/* ++ * RFC 5280 4.2.1.3 Key Usage ++ */ ++const char *keyUsage_oid = "2.5.29.15"; ++ ++/* ++ * RFC 5280 4.2.1.9 Basic Constraints ++ */ ++const char *basicConstraints_oid = "2.5.29.19"; ++ ++/* ++ * RFC 5280 4.2.1.12 Extended Key Usage ++ */ ++const char *extendedKeyUsage_oid = "2.5.29.37"; ++const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3"; ++ ++/* ++ * RFC 3279 2.3.1 ++ * ++ * The RSA public key MUST be encoded using the ASN.1 type RSAPublicKey: ++ * ++ * RSAPublicKey ::= SEQUENCE { ++ * modulus INTEGER, -- n ++ * publicExponent INTEGER } -- e ++ * ++ * where modulus is the modulus n, and publicExponent is the public ++ * exponent e. ++ */ ++static grub_err_t ++grub_parse_rsa_pubkey (grub_uint8_t * der, int dersize, ++ struct x509_certificate *certificate) ++{ ++ int result; ++ asn1_node spk = ASN1_TYPE_EMPTY; ++ grub_uint8_t *m_data, *e_data; ++ int m_size, e_size; ++ grub_err_t err = GRUB_ERR_NONE; ++ gcry_error_t gcry_err; ++ ++ result = ++ asn1_create_element (_gnutls_gnutls_asn, "GNUTLS.RSAPublicKey", &spk); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Cannot create storage for public key ASN.1 data"); ++ } ++ ++ result = asn1_der_decoding2 (&spk, der, &dersize, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Cannot decode certificate public key DER: %s", ++ asn1_error); ++ goto cleanup; ++ } ++ ++ m_data = ++ grub_asn1_allocate_and_read (spk, "modulus", "RSA modulus", &m_size); ++ if (!m_data) ++ { ++ err = grub_errno; ++ goto cleanup; ++ } ++ ++ e_data = ++ grub_asn1_allocate_and_read (spk, "publicExponent", "RSA public exponent", ++ &e_size); ++ if (!e_data) ++ { ++ err = grub_errno; ++ goto cleanup_m_data; ++ } ++ ++ /* ++ * convert m, e to mpi ++ * ++ * nscanned is not set for FMT_USG, it's only set for FMT_PGP, ++ * so we can't verify it ++ */ ++ gcry_err = ++ gcry_mpi_scan (&certificate->mpis[0], GCRYMPI_FMT_USG, m_data, m_size, ++ NULL); ++ if (gcry_err != GPG_ERR_NO_ERROR) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error loading RSA modulus into MPI structure: %d", ++ gcry_err); ++ goto cleanup_e_data; ++ } ++ ++ gcry_err = ++ gcry_mpi_scan (&certificate->mpis[1], GCRYMPI_FMT_USG, e_data, e_size, ++ NULL); ++ if (gcry_err != GPG_ERR_NO_ERROR) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error loading RSA exponent into MPI structure: %d", ++ gcry_err); ++ goto cleanup_m_mpi; ++ } ++ ++ grub_free (e_data); ++ grub_free (m_data); ++ asn1_delete_structure (&spk); ++ return GRUB_ERR_NONE; ++ ++cleanup_m_mpi: ++ gcry_mpi_release (certificate->mpis[0]); ++cleanup_e_data: ++ grub_free (e_data); ++cleanup_m_data: ++ grub_free (m_data); ++cleanup: ++ asn1_delete_structure (&spk); ++ return err; ++} ++ ++ ++/* ++ * RFC 5280: ++ * SubjectPublicKeyInfo ::= SEQUENCE { ++ * algorithm AlgorithmIdentifier, ++ * subjectPublicKey BIT STRING } ++ * ++ * AlgorithmIdentifiers come from RFC 3279, we are not strictly compilant as we ++ * only support RSA Encryption. ++ */ ++ ++static grub_err_t ++grub_x509_read_subject_public_key (asn1_node asn, ++ struct x509_certificate *results) ++{ ++ int result; ++ grub_err_t err; ++ const char *algo_name = ++ "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm"; ++ const char *params_name = ++ "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters"; ++ const char *pk_name = ++ "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey"; ++ char algo_oid[MAX_OID_LEN]; ++ int algo_size = sizeof (algo_oid); ++ char params_value[2]; ++ int params_size = sizeof (params_value); ++ grub_uint8_t *key_data = NULL; ++ int key_size = 0; ++ unsigned int key_type; ++ ++ /* algorithm: see notes for rsaEncryption_oid */ ++ result = asn1_read_value (asn, algo_name, algo_oid, &algo_size); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading x509 public key algorithm: %s", ++ asn1_strerror (result)); ++ } ++ ++ if (grub_strncmp (algo_oid, rsaEncryption_oid, sizeof (rsaEncryption_oid)) ++ != 0) ++ { ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Unsupported x509 public key algorithm: %s", ++ algo_oid); ++ } ++ ++ /* ++ * RFC 3279 2.3.1 ++ * The rsaEncryption OID is intended to be used in the algorithm field ++ * of a value of type AlgorithmIdentifier. The parameters field MUST ++ * have ASN.1 type NULL for this algorithm identifier. ++ */ ++ result = asn1_read_value (asn, params_name, params_value, ¶ms_size); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading x509 public key parameters: %s", ++ asn1_strerror (result)); ++ } ++ ++ if (params_value[0] != ASN1_TAG_NULL) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Invalid x509 public key parameters: expected NULL"); ++ } ++ ++ /* ++ * RFC 3279 2.3.1: The DER encoded RSAPublicKey is the value of the BIT ++ * STRING subjectPublicKey. ++ */ ++ result = asn1_read_value_type (asn, pk_name, NULL, &key_size, &key_type); ++ if (result != ASN1_MEM_ERROR) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading size of x509 public key: %s", ++ asn1_strerror (result)); ++ } ++ if (key_type != ASN1_ETYPE_BIT_STRING) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected ASN.1 type when reading x509 public key: %x", ++ key_type); ++ } ++ ++ /* length is in bits */ ++ key_size = (key_size + 7) / 8; ++ ++ key_data = grub_malloc (key_size); ++ if (!key_data) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Out of memory for x509 public key"); ++ } ++ ++ result = asn1_read_value (asn, pk_name, key_data, &key_size); ++ if (result != ASN1_SUCCESS) ++ { ++ grub_free (key_data); ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading public key data"); ++ } ++ key_size = (key_size + 7) / 8; ++ ++ err = grub_parse_rsa_pubkey (key_data, key_size, results); ++ grub_free (key_data); ++ ++ return err; ++} ++ ++/* Decode a string as defined in Appendix A */ ++static grub_err_t ++decode_string (char *der, int der_size, char **string, ++ grub_size_t * string_size) ++{ ++ asn1_node strasn; ++ int result; ++ char *choice; ++ int choice_size = 0; ++ int tmp_size = 0; ++ grub_err_t err = GRUB_ERR_NONE; ++ ++ result = ++ asn1_create_element (_gnutls_pkix_asn, "PKIX1.DirectoryString", &strasn); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for certificate: %s", ++ asn1_strerror (result)); ++ } ++ ++ result = asn1_der_decoding2 (&strasn, der, &der_size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Could not parse DER for DirectoryString: %s", ++ asn1_error); ++ goto cleanup; ++ } ++ ++ choice = ++ grub_asn1_allocate_and_read (strasn, "", "DirectoryString choice", ++ &choice_size); ++ if (!choice) ++ { ++ err = grub_errno; ++ goto cleanup; ++ } ++ ++ if (grub_strncmp ("utf8String", choice, choice_size)) ++ { ++ err = ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Only UTF-8 DirectoryStrings are supported, got %s", ++ choice); ++ goto cleanup_choice; ++ } ++ ++ result = asn1_read_value (strasn, "utf8String", NULL, &tmp_size); ++ if (result != ASN1_MEM_ERROR) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading size of UTF-8 string: %s", ++ asn1_strerror (result)); ++ goto cleanup_choice; ++ } ++ ++ /* read size does not include trailing null */ ++ tmp_size++; ++ ++ *string = grub_malloc (tmp_size); ++ if (!*string) ++ { ++ err = ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Cannot allocate memory for DirectoryString contents"); ++ goto cleanup_choice; ++ } ++ ++ result = asn1_read_value (strasn, "utf8String", *string, &tmp_size); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading out UTF-8 string in DirectoryString: %s", ++ asn1_strerror (result)); ++ grub_free (*string); ++ goto cleanup_choice; ++ } ++ *string_size = tmp_size + 1; ++ (*string)[tmp_size] = '\0'; ++ ++cleanup_choice: ++ grub_free (choice); ++cleanup: ++ asn1_delete_structure (&strasn); ++ return err; ++} ++ ++/* ++ * TBSCertificate ::= SEQUENCE { ++ * version [0] EXPLICIT Version DEFAULT v1, ++ * ... ++ * ++ * Version ::= INTEGER { v1(0), v2(1), v3(2) } ++ */ ++static grub_err_t ++check_version (asn1_node certificate) ++{ ++ int rc; ++ const char *name = "tbsCertificate.version"; ++ grub_uint8_t version; ++ int len = 1; ++ ++ rc = asn1_read_value (certificate, name, &version, &len); ++ ++ /* require version 3 */ ++ if (rc != ASN1_SUCCESS || len != 1) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading certificate version"); ++ ++ if (version != 0x02) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Invalid x509 certificate version, expected v3 (0x02), got 0x%02x", ++ version); ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* ++ * This is an X.501 Name, which is complex. ++ * ++ * For simplicity, we extract only the CN. ++ */ ++static grub_err_t ++read_name (asn1_node asn, const char *name_path, char **name, ++ grub_size_t * name_size) ++{ ++ int seq_components, set_components; ++ int result; ++ int i, j; ++ char *top_path, *set_path, *type_path, *val_path; ++ char type[MAX_OID_LEN]; ++ int type_len = sizeof (type); ++ int string_size = 0; ++ char *string_der; ++ grub_err_t err; ++ ++ *name = NULL; ++ ++ top_path = grub_xasprintf ("%s.rdnSequence", name_path); ++ if (!top_path) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate memory for %s name parsing path", ++ name_path); ++ ++ result = asn1_number_of_elements (asn, top_path, &seq_components); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error counting name components: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ for (i = 1; i <= seq_components; i++) ++ { ++ set_path = grub_xasprintf ("%s.?%d", top_path, i); ++ if (!set_path) ++ { ++ err = ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate memory for %s name set parsing path", ++ name_path); ++ goto cleanup_set; ++ } ++ /* this brings us, hopefully, to a set */ ++ result = asn1_number_of_elements (asn, set_path, &set_components); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error counting name sub-components components (element %d): %s", ++ i, asn1_strerror (result)); ++ goto cleanup_set; ++ } ++ for (j = 1; j <= set_components; j++) ++ { ++ type_path = grub_xasprintf ("%s.?%d.?%d.type", top_path, i, j); ++ if (!type_path) ++ { ++ err = ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate memory for %s name component type path", ++ name_path); ++ goto cleanup_set; ++ } ++ type_len = sizeof (type); ++ result = asn1_read_value (asn, type_path, type, &type_len); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading %s name component type: %s", ++ name_path, asn1_strerror (result)); ++ goto cleanup_type; ++ } ++ ++ if (grub_strncmp (type, commonName_oid, type_len) != 0) ++ { ++ grub_free (type_path); ++ continue; ++ } ++ ++ val_path = grub_xasprintf ("%s.?%d.?%d.value", top_path, i, j); ++ if (!val_path) ++ { ++ err = ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate memory for %s name component value path", ++ name_path); ++ goto cleanup_set; ++ } ++ ++ string_der = ++ grub_asn1_allocate_and_read (asn, val_path, name_path, ++ &string_size); ++ if (!string_der) ++ { ++ err = grub_errno; ++ goto cleanup_val_path; ++ } ++ ++ err = decode_string (string_der, string_size, name, name_size); ++ if (err) ++ goto cleanup_string; ++ ++ grub_free (string_der); ++ grub_free (type_path); ++ grub_free (val_path); ++ break; ++ } ++ grub_free (set_path); ++ ++ if (*name) ++ break; ++ } ++ ++ return GRUB_ERR_NONE; ++ ++cleanup_string: ++ grub_free (string_der); ++cleanup_val_path: ++ grub_free (val_path); ++cleanup_type: ++ grub_free (type_path); ++cleanup_set: ++ grub_free (set_path); ++cleanup: ++ grub_free (top_path); ++ return err; ++} ++ ++/* ++ * details here ++ */ ++static grub_err_t ++verify_key_usage (grub_uint8_t * value, int value_size) ++{ ++ asn1_node usageasn; ++ int result; ++ grub_err_t err = GRUB_ERR_NONE; ++ grub_uint8_t usage = 0xff; ++ int usage_size = 1; ++ ++ result = ++ asn1_create_element (_gnutls_pkix_asn, "PKIX1.KeyUsage", &usageasn); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for key usage"); ++ } ++ ++ result = asn1_der_decoding2 (&usageasn, value, &value_size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error parsing DER for Key Usage: %s", asn1_error); ++ goto cleanup; ++ } ++ ++ result = asn1_read_value (usageasn, "", &usage, &usage_size); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading Key Usage value: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ /* Only the first bit is permitted to be set */ ++ if (usage != 0x80) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected Key Usage value: %x", ++ usage); ++ goto cleanup; ++ } ++ ++cleanup: ++ asn1_delete_structure (&usageasn); ++ return err; ++} ++ ++/* ++ * BasicConstraints ::= SEQUENCE { ++ * cA BOOLEAN DEFAULT FALSE, ++ * pathLenConstraint INTEGER (0..MAX) OPTIONAL } ++ */ ++static grub_err_t ++verify_basic_constraints (grub_uint8_t * value, int value_size) ++{ ++ asn1_node basicasn; ++ int result; ++ grub_err_t err = GRUB_ERR_NONE; ++ char cA[6]; /* FALSE or TRUE */ ++ int cA_size = sizeof (cA); ++ ++ result = ++ asn1_create_element (_gnutls_pkix_asn, "PKIX1.BasicConstraints", ++ &basicasn); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for Basic Constraints"); ++ } ++ ++ result = asn1_der_decoding2 (&basicasn, value, &value_size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error parsing DER for Basic Constraints: %s", ++ asn1_error); ++ goto cleanup; ++ } ++ ++ result = asn1_read_value (basicasn, "cA", cA, &cA_size); ++ if (result == ASN1_ELEMENT_NOT_FOUND) ++ { ++ /* Not present, default is False, so this is OK */ ++ err = GRUB_ERR_NONE; ++ goto cleanup; ++ } ++ else if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading Basic Constraints cA value: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ /* The certificate must not be a CA certificate */ ++ if (grub_strncmp ("FALSE", cA, cA_size) != 0) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected CA value: %s", ++ cA); ++ goto cleanup; ++ } ++ ++cleanup: ++ asn1_delete_structure (&basicasn); ++ return err; ++} ++ ++/* ++ * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId ++ * ++ * KeyPurposeId ::= OBJECT IDENTIFIER ++ */ ++static grub_err_t ++verify_extended_key_usage (grub_uint8_t * value, int value_size) ++{ ++ asn1_node extendedasn; ++ int result, count; ++ grub_err_t err = GRUB_ERR_NONE; ++ char usage[MAX_OID_LEN]; ++ int usage_size = sizeof (usage); ++ ++ result = ++ asn1_create_element (_gnutls_pkix_asn, "PKIX1.ExtKeyUsageSyntax", ++ &extendedasn); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for Extended Key Usage"); ++ } ++ ++ result = asn1_der_decoding2 (&extendedasn, value, &value_size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error parsing DER for Extended Key Usage: %s", ++ asn1_error); ++ goto cleanup; ++ } ++ ++ /* ++ * If EKUs are present, there must be exactly 1 and it must be a ++ * codeSigning usage. ++ */ ++ result = asn1_number_of_elements(extendedasn, "", &count); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error counting number of Extended Key Usages: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ result = asn1_read_value (extendedasn, "?1", usage, &usage_size); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading Extended Key Usage: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) != 0) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected Extended Key Usage OID, got: %s", ++ usage); ++ goto cleanup; ++ } ++ ++cleanup: ++ asn1_delete_structure (&extendedasn); ++ return err; ++} ++ ++/* ++ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension ++ * ++ * Extension ::= SEQUENCE { ++ * extnID OBJECT IDENTIFIER, ++ * critical BOOLEAN DEFAULT FALSE, ++ * extnValue OCTET STRING ++ * -- contains the DER encoding of an ASN.1 value ++ * -- corresponding to the extension type identified ++ * -- by extnID ++ * } ++ * ++ * We require that a certificate: ++ * - contain the Digital Signature usage only ++ * - not be a CA ++ * - MUST not contain any other critical extensions (RFC 5280 s 4.2) ++ */ ++static grub_err_t ++verify_extensions (asn1_node cert) ++{ ++ int result; ++ int ext, num_extensions = 0; ++ int usage_present = 0, constraints_present = 0, extended_usage_present = 0; ++ char *oid_path, *critical_path, *value_path; ++ char extnID[MAX_OID_LEN]; ++ int extnID_size; ++ grub_err_t err; ++ char critical[6]; /* we get either "TRUE" or "FALSE" */ ++ int critical_size; ++ grub_uint8_t *value; ++ int value_size; ++ ++ result = ++ asn1_number_of_elements (cert, "tbsCertificate.extensions", ++ &num_extensions); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error counting number of extensions: %s", ++ asn1_strerror (result)); ++ } ++ ++ if (num_extensions < 2) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Insufficient number of extensions for certificate, need at least 2, got %d", ++ num_extensions); ++ } ++ ++ for (ext = 1; ext <= num_extensions; ext++) ++ { ++ oid_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnID", ext); ++ ++ extnID_size = sizeof (extnID); ++ result = asn1_read_value (cert, oid_path, extnID, &extnID_size); ++ if (result != GRUB_ERR_NONE) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading extension OID: %s", ++ asn1_strerror (result)); ++ goto cleanup_oid_path; ++ } ++ ++ critical_path = ++ grub_xasprintf ("tbsCertificate.extensions.?%d.critical", ext); ++ critical_size = sizeof (critical); ++ result = ++ asn1_read_value (cert, critical_path, critical, &critical_size); ++ if (result == ASN1_ELEMENT_NOT_FOUND) ++ { ++ critical[0] = '\0'; ++ } ++ else if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading extension criticality: %s", ++ asn1_strerror (result)); ++ goto cleanup_critical_path; ++ } ++ ++ value_path = ++ grub_xasprintf ("tbsCertificate.extensions.?%d.extnValue", ext); ++ value = ++ grub_asn1_allocate_and_read (cert, value_path, ++ "certificate extension value", ++ &value_size); ++ if (!value) ++ { ++ err = grub_errno; ++ goto cleanup_value_path; ++ } ++ ++ /* ++ * Now we must see if we recognise the OID. ++ * If we have an unrecognised critical extension we MUST bail. ++ */ ++ if (grub_strncmp (keyUsage_oid, extnID, extnID_size) == 0) ++ { ++ err = verify_key_usage (value, value_size); ++ if (err != GRUB_ERR_NONE) ++ { ++ goto cleanup_value; ++ } ++ usage_present++; ++ } ++ else if (grub_strncmp (basicConstraints_oid, extnID, extnID_size) == 0) ++ { ++ err = verify_basic_constraints (value, value_size); ++ if (err != GRUB_ERR_NONE) ++ { ++ goto cleanup_value; ++ } ++ constraints_present++; ++ } ++ else if (grub_strncmp (extendedKeyUsage_oid, extnID, extnID_size) == 0) ++ { ++ err = verify_extended_key_usage (value, value_size); ++ if (err != GRUB_ERR_NONE) ++ { ++ goto cleanup_value; ++ } ++ extended_usage_present++; ++ } ++ else if (grub_strncmp ("TRUE", critical, critical_size) == 0) ++ { ++ /* ++ * per the RFC, we must not process a certificate with ++ * a critical extension we do not understand. ++ */ ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unhandled critical x509 extension with OID %s", ++ extnID); ++ goto cleanup_value; ++ } ++ ++ grub_free (value); ++ grub_free (value_path); ++ grub_free (critical_path); ++ grub_free (oid_path); ++ } ++ ++ if (usage_present != 1) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected number of Key Usage extensions - expected 1, got %d", ++ usage_present); ++ } ++ if (constraints_present != 1) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected number of basic constraints extensions - expected 1, got %d", ++ constraints_present); ++ } ++ if (extended_usage_present > 1) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected number of Extended Key Usage extensions - expected 0 or 1, got %d", ++ extended_usage_present); ++ } ++ return GRUB_ERR_NONE; ++ ++cleanup_value: ++ grub_free (value); ++cleanup_value_path: ++ grub_free (value_path); ++cleanup_critical_path: ++ grub_free (critical_path); ++cleanup_oid_path: ++ grub_free (oid_path); ++ return err; ++} ++ ++/* ++ * Parse a certificate whose DER-encoded form is in @data, of size @data_size. ++ * Return the results in @results, which must point to an allocated x509 certificate. ++ */ ++grub_err_t ++certificate_import (void *data, grub_size_t data_size, ++ struct x509_certificate *results) ++{ ++ int result = 0; ++ asn1_node cert; ++ grub_err_t err; ++ int size; ++ int tmp_size; ++ ++ if (data_size > GRUB_INT_MAX) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ "Cannot parse a certificate where data size > INT_MAX"); ++ size = (int) data_size; ++ ++ result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.Certificate", &cert); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for certificate: %s", ++ asn1_strerror (result)); ++ } ++ ++ result = asn1_der_decoding2 (&cert, data, &size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Could not parse DER for certificate: %s", asn1_error); ++ goto cleanup; ++ } ++ ++ /* ++ * TBSCertificate ::= SEQUENCE { ++ * version [0] EXPLICIT Version DEFAULT v1 ++ */ ++ err = check_version (cert); ++ if (err != GRUB_ERR_NONE) ++ { ++ goto cleanup; ++ } ++ ++ /* ++ * serialNumber CertificateSerialNumber, ++ * ++ * CertificateSerialNumber ::= INTEGER ++ */ ++ results->serial = ++ grub_asn1_allocate_and_read (cert, "tbsCertificate.serialNumber", ++ "certificate serial number", &tmp_size); ++ if (!results->serial) ++ { ++ err = grub_errno; ++ goto cleanup; ++ } ++ /* ++ * It's safe to cast the signed int to an unsigned here, we know ++ * length is non-negative ++ */ ++ results->serial_len = tmp_size; ++ ++ /* ++ * signature AlgorithmIdentifier, ++ * ++ * We don't load the signature or issuer at the moment, ++ * as we don't attempt x509 verification. ++ */ ++ ++ /* ++ * issuer Name, ++ * ++ * The RFC only requires the serial number to be unique within ++ * issuers, so to avoid ambiguity we _technically_ ought to make ++ * this available. ++ */ ++ ++ /* ++ * validity Validity, ++ * ++ * Validity ::= SEQUENCE { ++ * notBefore Time, ++ * notAfter Time } ++ * ++ * We can't validate this reasonably, we have no true time source on several ++ * platforms. For now we do not parse them. ++ */ ++ ++ /* ++ * subject Name, ++ * ++ * This is an X501 name, we parse out just the CN. ++ */ ++ err = ++ read_name (cert, "tbsCertificate.subject", &results->subject, ++ &results->subject_len); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup_serial; ++ ++ /* ++ * TBSCertificate ::= SEQUENCE { ++ * ... ++ * subjectPublicKeyInfo SubjectPublicKeyInfo, ++ * ... ++ */ ++ err = grub_x509_read_subject_public_key (cert, results); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup_name; ++ ++ /* ++ * TBSCertificate ::= SEQUENCE { ++ * ... ++ * extensions [3] EXPLICIT Extensions OPTIONAL ++ * -- If present, version MUST be v3 ++ * } ++ */ ++ ++ err = verify_extensions (cert); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup_name; ++ ++ ++ /* ++ * We do not read or check the signature on the certificate: ++ * as discussed we do not try to validate the certificate but trust ++ * it implictly. ++ */ ++ ++ asn1_delete_structure (&cert); ++ return GRUB_ERR_NONE; ++ ++ ++cleanup_name: ++ grub_free (results->subject); ++cleanup_serial: ++ grub_free (results->serial); ++cleanup: ++ asn1_delete_structure (&cert); ++ return err; ++} ++ ++/* ++ * Release all the storage associated with the x509 certificate. ++ * If the caller dynamically allocated the certificate, it must free it. ++ * The caller is also responsible for maintenance of the linked list. ++ */ ++void ++certificate_release (struct x509_certificate *cert) ++{ ++ grub_free (cert->subject); ++ grub_free (cert->serial); ++ gcry_mpi_release (cert->mpis[0]); ++ gcry_mpi_release (cert->mpis[1]); ++} +diff --git a/grub-core/lib/backtrace.c b/grub-core/commands/backtrace.c +similarity index 97% +rename from grub-core/lib/backtrace.c +rename to grub-core/commands/backtrace.c +index 825a8800e..8b5ec3913 100644 +--- a/grub-core/lib/backtrace.c ++++ b/grub-core/commands/backtrace.c +@@ -29,6 +29,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + void + grub_backtrace_print_address (void *addr) + { ++#ifndef GRUB_UTIL + grub_dl_t mod; + + FOR_DL_MODULES (mod) +@@ -44,6 +45,7 @@ grub_backtrace_print_address (void *addr) + } + } + ++#endif + grub_printf ("%p", addr); + } + +@@ -52,7 +54,7 @@ grub_cmd_backtrace (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) + { +- grub_backtrace (); ++ grub_backtrace (1); + return 0; + } + +diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c +new file mode 100644 +index 000000000..6e398fc17 +--- /dev/null ++++ b/grub-core/commands/blscfg.c +@@ -0,0 +1,1221 @@ ++/*-*- Mode: C; c-basic-offset: 2; indent-tabs-mode: t -*-*/ ++ ++/* bls.c - implementation of the boot loader spec */ ++ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++#include "loadenv.h" ++ ++#define GRUB_BLS_CONFIG_PATH "/loader/entries/" ++ ++#ifdef GRUB_MACHINE_EMU ++#define GRUB_BOOT_DEVICE "/boot" ++#else ++#define GRUB_BOOT_DEVICE "($root)" ++#endif ++ ++struct keyval ++{ ++ const char *key; ++ char *val; ++}; ++ ++static struct bls_entry *entries = NULL; ++ ++/* Cache probing in frob_boot_device(). Used for linux entry also. ++ * Always true in non-emu, meaning to prefix things with GRUB_BOOT_DEVICE. */ ++static int separate_boot = -1; ++ ++#define FOR_BLS_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries) ++ ++/* BLS appears to make paths relative to the filesystem that snippets are ++ * on, not /. Attempt to cope. */ ++static char *frob_boot_device(char *tmp) ++{ ++#ifdef GRUB_MACHINE_EMU ++ grub_file_t f; ++ char *line = NULL; ++ ++ if (separate_boot != -1) ++ goto probed; ++ ++ separate_boot = 0; ++ ++ f = grub_file_open ("/proc/mounts", GRUB_FILE_TYPE_CONFIG); ++ if (f == NULL) ++ goto probed; ++ ++ while ((line = grub_file_getline (f))) ++ { ++ if (grub_strstr (line, " " GRUB_BOOT_DEVICE " ")) ++ { ++ separate_boot = 1; ++ grub_free (line); ++ break; ++ } ++ ++ grub_free(line); ++ } ++ ++ grub_file_close (f); ++ probed: ++ if (!separate_boot) ++ return grub_stpcpy (tmp, " "); ++#endif ++ ++ return grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); ++} ++ ++static int bls_add_keyval(struct bls_entry *entry, char *key, char *val) ++{ ++ char *k, *v; ++ struct keyval **kvs, *kv; ++ int new_n = entry->nkeyvals + 1; ++ ++ kvs = grub_realloc (entry->keyvals, new_n * sizeof (struct keyval *)); ++ if (!kvs) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't find space for BLS entry"); ++ entry->keyvals = kvs; ++ ++ kv = grub_malloc (sizeof (struct keyval)); ++ if (!kv) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't find space for BLS entry"); ++ ++ k = grub_strdup (key); ++ if (!k) ++ { ++ grub_free (kv); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't find space for BLS entry"); ++ } ++ ++ v = grub_strdup (val); ++ if (!v) ++ { ++ grub_free (k); ++ grub_free (kv); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't find space for BLS entry"); ++ } ++ ++ kv->key = k; ++ kv->val = v; ++ ++ entry->keyvals[entry->nkeyvals] = kv; ++ grub_dprintf("blscfg", "new keyval at %p:%s:%s\n", entry->keyvals[entry->nkeyvals], k, v); ++ entry->nkeyvals = new_n; ++ ++ return 0; ++} ++ ++/* Find they value of the key named by keyname. If there are allowed to be ++ * more than one, pass a pointer to an int set to -1 the first time, and pass ++ * the same pointer through each time after, and it'll return them in sorted ++ * order as defined in the BLS fragment file */ ++static char *bls_get_val(struct bls_entry *entry, const char *keyname, int *last) ++{ ++ int idx, start = 0; ++ struct keyval *kv = NULL; ++ ++ if (last) ++ start = *last + 1; ++ ++ for (idx = start; idx < entry->nkeyvals; idx++) { ++ kv = entry->keyvals[idx]; ++ ++ if (!grub_strcmp (keyname, kv->key)) ++ break; ++ } ++ ++ if (idx == entry->nkeyvals) { ++ if (last) ++ *last = -1; ++ return NULL; ++ } ++ ++ if (last) ++ *last = idx; ++ ++ return kv->val; ++} ++ ++#define goto_return(x) ({ ret = (x); goto finish; }) ++ ++/* compare alpha and numeric segments of two versions */ ++/* return 1: a is newer than b */ ++/* 0: a and b are the same version */ ++/* -1: b is newer than a */ ++static int vercmp(const char * a, const char * b) ++{ ++ char oldch1, oldch2; ++ char *abuf, *bbuf; ++ char *str1, *str2; ++ char * one, * two; ++ int rc; ++ int isnum; ++ int ret = 0; ++ ++ grub_dprintf("blscfg", "%s comparing %s and %s\n", __func__, a, b); ++ if (!grub_strcmp(a, b)) ++ return 0; ++ ++ abuf = grub_malloc(grub_strlen(a) + 1); ++ bbuf = grub_malloc(grub_strlen(b) + 1); ++ str1 = abuf; ++ str2 = bbuf; ++ grub_strcpy(str1, a); ++ grub_strcpy(str2, b); ++ ++ one = str1; ++ two = str2; ++ ++ /* loop through each version segment of str1 and str2 and compare them */ ++ while (*one || *two) { ++ while (*one && !grub_isalnum(*one) && *one != '~' && *one != '+') one++; ++ while (*two && !grub_isalnum(*two) && *two != '~' && *two != '+') two++; ++ ++ /* handle the tilde separator, it sorts before everything else */ ++ if (*one == '~' || *two == '~') { ++ if (*one != '~') goto_return (1); ++ if (*two != '~') goto_return (-1); ++ one++; ++ two++; ++ continue; ++ } ++ ++ /* ++ * Handle plus separator. Concept is the same as tilde, ++ * except that if one of the strings ends (base version), ++ * the other is considered as higher version. ++ */ ++ if (*one == '+' || *two == '+') { ++ if (!*one) return -1; ++ if (!*two) return 1; ++ if (*one != '+') goto_return (1); ++ if (*two != '+') goto_return (-1); ++ one++; ++ two++; ++ continue; ++ } ++ ++ /* If we ran to the end of either, we are finished with the loop */ ++ if (!(*one && *two)) break; ++ ++ str1 = one; ++ str2 = two; ++ ++ /* grab first completely alpha or completely numeric segment */ ++ /* leave one and two pointing to the start of the alpha or numeric */ ++ /* segment and walk str1 and str2 to end of segment */ ++ if (grub_isdigit(*str1)) { ++ while (*str1 && grub_isdigit(*str1)) str1++; ++ while (*str2 && grub_isdigit(*str2)) str2++; ++ isnum = 1; ++ } else { ++ while (*str1 && grub_isalpha(*str1)) str1++; ++ while (*str2 && grub_isalpha(*str2)) str2++; ++ isnum = 0; ++ } ++ ++ /* save character at the end of the alpha or numeric segment */ ++ /* so that they can be restored after the comparison */ ++ oldch1 = *str1; ++ *str1 = '\0'; ++ oldch2 = *str2; ++ *str2 = '\0'; ++ ++ /* this cannot happen, as we previously tested to make sure that */ ++ /* the first string has a non-null segment */ ++ if (one == str1) goto_return(-1); /* arbitrary */ ++ ++ /* take care of the case where the two version segments are */ ++ /* different types: one numeric, the other alpha (i.e. empty) */ ++ /* numeric segments are always newer than alpha segments */ ++ /* XXX See patch #60884 (and details) from bugzilla #50977. */ ++ if (two == str2) goto_return (isnum ? 1 : -1); ++ ++ if (isnum) { ++ grub_size_t onelen, twolen; ++ /* this used to be done by converting the digit segments */ ++ /* to ints using atoi() - it's changed because long */ ++ /* digit segments can overflow an int - this should fix that. */ ++ ++ /* throw away any leading zeros - it's a number, right? */ ++ while (*one == '0') one++; ++ while (*two == '0') two++; ++ ++ /* whichever number has more digits wins */ ++ onelen = grub_strlen(one); ++ twolen = grub_strlen(two); ++ if (onelen > twolen) goto_return (1); ++ if (twolen > onelen) goto_return (-1); ++ } ++ ++ /* grub_strcmp will return which one is greater - even if the two */ ++ /* segments are alpha or if they are numeric. don't return */ ++ /* if they are equal because there might be more segments to */ ++ /* compare */ ++ rc = grub_strcmp(one, two); ++ if (rc) goto_return (rc < 1 ? -1 : 1); ++ ++ /* restore character that was replaced by null above */ ++ *str1 = oldch1; ++ one = str1; ++ *str2 = oldch2; ++ two = str2; ++ } ++ ++ /* this catches the case where all numeric and alpha segments have */ ++ /* compared identically but the segment sepparating characters were */ ++ /* different */ ++ if ((!*one) && (!*two)) goto_return (0); ++ ++ /* whichever version still has characters left over wins */ ++ if (!*one) goto_return (-1); else goto_return (1); ++ ++finish: ++ grub_free (abuf); ++ grub_free (bbuf); ++ return ret; ++} ++ ++/* returns name/version/release */ ++/* NULL string pointer returned if nothing found */ ++static void ++split_package_string (char *package_string, char **name, ++ char **version, char **release) ++{ ++ char *package_version, *package_release; ++ ++ /* Release */ ++ package_release = grub_strrchr (package_string, '-'); ++ ++ if (package_release != NULL) ++ *package_release++ = '\0'; ++ ++ *release = package_release; ++ ++ if (name == NULL) ++ { ++ *version = package_string; ++ } ++ else ++ { ++ /* Version */ ++ package_version = grub_strrchr(package_string, '-'); ++ ++ if (package_version != NULL) ++ *package_version++ = '\0'; ++ ++ *version = package_version; ++ /* Name */ ++ *name = package_string; ++ } ++ ++ /* Bubble up non-null values from release to name */ ++ if (name != NULL && *name == NULL) ++ { ++ *name = (*version == NULL ? *release : *version); ++ *version = *release; ++ *release = NULL; ++ } ++ if (*version == NULL) ++ { ++ *version = *release; ++ *release = NULL; ++ } ++} ++ ++static int ++split_cmp(char *nvr0, char *nvr1, int has_name) ++{ ++ int ret = 0; ++ char *name0, *version0, *release0; ++ char *name1, *version1, *release1; ++ ++ split_package_string(nvr0, has_name ? &name0 : NULL, &version0, &release0); ++ split_package_string(nvr1, has_name ? &name1 : NULL, &version1, &release1); ++ ++ if (has_name) ++ { ++ ret = vercmp(name0 == NULL ? "" : name0, ++ name1 == NULL ? "" : name1); ++ if (ret != 0) ++ return ret; ++ } ++ ++ ret = vercmp(version0 == NULL ? "" : version0, ++ version1 == NULL ? "" : version1); ++ if (ret != 0) ++ return ret; ++ ++ ret = vercmp(release0 == NULL ? "" : release0, ++ release1 == NULL ? "" : release1); ++ return ret; ++} ++ ++/* return 1: e0 is newer than e1 */ ++/* 0: e0 and e1 are the same version */ ++/* -1: e1 is newer than e0 */ ++static int bls_cmp(const struct bls_entry *e0, const struct bls_entry *e1) ++{ ++ char *id0, *id1; ++ int r; ++ ++ id0 = grub_strdup(e0->filename); ++ id1 = grub_strdup(e1->filename); ++ ++ r = split_cmp(id0, id1, 1); ++ ++ grub_free(id0); ++ grub_free(id1); ++ ++ return r; ++} ++ ++static void list_add_tail(struct bls_entry *head, struct bls_entry *item) ++{ ++ item->next = head; ++ if (head->prev) ++ head->prev->next = item; ++ item->prev = head->prev; ++ head->prev = item; ++} ++ ++static int bls_add_entry(struct bls_entry *entry) ++{ ++ struct bls_entry *e, *last = NULL; ++ int rc; ++ ++ if (!entries) { ++ grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename); ++ entries = entry; ++ return 0; ++ } ++ ++ FOR_BLS_ENTRIES(e) { ++ rc = bls_cmp(entry, e); ++ ++ if (!rc) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ if (rc == 1) { ++ grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename); ++ list_add_tail (e, entry); ++ if (e == entries) { ++ entries = entry; ++ entry->prev = NULL; ++ } ++ return 0; ++ } ++ last = e; ++ } ++ ++ if (last) { ++ grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename); ++ last->next = entry; ++ entry->prev = last; ++ } ++ ++ return 0; ++} ++ ++struct read_entry_info { ++ const char *devid; ++ const char *dirname; ++ grub_file_t file; ++}; ++ ++static int read_entry ( ++ const char *filename, ++ const struct grub_dirhook_info *dirhook_info UNUSED, ++ void *data) ++{ ++ grub_size_t m = 0, n, clip = 0; ++ int rc = 0; ++ char *p = NULL; ++ grub_file_t f = NULL; ++ struct bls_entry *entry; ++ struct read_entry_info *info = (struct read_entry_info *)data; ++ ++ grub_dprintf ("blscfg", "filename: \"%s\"\n", filename); ++ ++ n = grub_strlen (filename); ++ ++ if (info->file) ++ { ++ f = info->file; ++ } ++ else ++ { ++ if (filename[0] == '.') ++ return 0; ++ ++ if (n <= 5) ++ return 0; ++ ++ if (grub_strcmp (filename + n - 5, ".conf") != 0) ++ return 0; ++ ++ p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename); ++ ++ f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG); ++ if (!f) ++ goto finish; ++ } ++ ++ entry = grub_zalloc (sizeof (*entry)); ++ if (!entry) ++ goto finish; ++ ++ if (info->file) ++ { ++ char *slash; ++ ++ if (n > 5 && !grub_strcmp (filename + n - 5, ".conf") == 0) ++ clip = 5; ++ ++ slash = grub_strrchr (filename, '/'); ++ if (!slash) ++ slash = grub_strrchr (filename, '\\'); ++ ++ while (*slash == '/' || *slash == '\\') ++ slash++; ++ ++ m = slash ? slash - filename : 0; ++ } ++ else ++ { ++ m = 0; ++ clip = 5; ++ } ++ n -= m; ++ ++ entry->filename = grub_strndup(filename + m, n - clip); ++ if (!entry->filename) ++ goto finish; ++ ++ entry->filename[n - 5] = '\0'; ++ ++ for (;;) ++ { ++ char *buf; ++ char *separator; ++ ++ buf = grub_file_getline (f); ++ if (!buf) ++ break; ++ ++ while (buf && buf[0] && (buf[0] == ' ' || buf[0] == '\t')) ++ buf++; ++ if (buf[0] == '#') ++ continue; ++ ++ separator = grub_strchr (buf, ' '); ++ ++ if (!separator) ++ separator = grub_strchr (buf, '\t'); ++ ++ if (!separator || separator[1] == '\0') ++ { ++ grub_free (buf); ++ break; ++ } ++ ++ separator[0] = '\0'; ++ ++ do { ++ separator++; ++ } while (*separator == ' ' || *separator == '\t'); ++ ++ rc = bls_add_keyval (entry, buf, separator); ++ grub_free (buf); ++ if (rc < 0) ++ break; ++ } ++ ++ if (!rc) ++ bls_add_entry(entry); ++ ++finish: ++ if (p) ++ grub_free (p); ++ ++ if (f) ++ grub_file_close (f); ++ ++ return 0; ++} ++ ++static grub_envblk_t saved_env = NULL; ++ ++static int UNUSED ++save_var (const char *name, const char *value, void *whitelist UNUSED) ++{ ++ const char *val = grub_env_get (name); ++ grub_dprintf("blscfg", "saving \"%s\"\n", name); ++ ++ if (val) ++ grub_envblk_set (saved_env, name, value); ++ ++ return 0; ++} ++ ++static int UNUSED ++unset_var (const char *name, const char *value UNUSED, void *whitelist) ++{ ++ grub_dprintf("blscfg", "restoring \"%s\"\n", name); ++ if (! whitelist) ++ { ++ grub_env_unset (name); ++ return 0; ++ } ++ ++ if (test_whitelist_membership (name, ++ (const grub_env_whitelist_t *) whitelist)) ++ grub_env_unset (name); ++ ++ return 0; ++} ++ ++static char **bls_make_list (struct bls_entry *entry, const char *key, int *num) ++{ ++ int last = -1; ++ char *val; ++ ++ int nlist = 0; ++ char **list = NULL; ++ ++ list = grub_malloc (sizeof (char *)); ++ if (!list) ++ return NULL; ++ list[0] = NULL; ++ ++ while (1) ++ { ++ char **new; ++ ++ val = bls_get_val (entry, key, &last); ++ if (!val) ++ break; ++ ++ new = grub_realloc (list, (nlist + 2) * sizeof (char *)); ++ if (!new) ++ break; ++ ++ list = new; ++ list[nlist++] = val; ++ list[nlist] = NULL; ++ } ++ ++ if (!nlist) ++ { ++ grub_free (list); ++ return NULL; ++ } ++ ++ if (num) ++ *num = nlist; ++ ++ return list; ++} ++ ++static char *field_append(bool is_var, char *buffer, const char *start, const char *end) ++{ ++ char *tmp = grub_strndup(start, end - start + 1); ++ const char *field = tmp; ++ int term = is_var ? 2 : 1; ++ ++ if (is_var) { ++ field = grub_env_get (tmp); ++ if (!field) ++ return buffer; ++ } ++ ++ if (!buffer) ++ buffer = grub_zalloc (grub_strlen(field) + term); ++ else ++ buffer = grub_realloc (buffer, grub_strlen(buffer) + grub_strlen(field) + term); ++ ++ if (!buffer) ++ return NULL; ++ ++ tmp = buffer + grub_strlen(buffer); ++ tmp = grub_stpcpy (tmp, field); ++ ++ if (is_var) ++ tmp = grub_stpcpy (tmp, " "); ++ ++ return buffer; ++} ++ ++static char *expand_val(const char *value) ++{ ++ char *buffer = NULL; ++ const char *start = value; ++ const char *end = value; ++ bool is_var = false; ++ ++ if (!value) ++ return NULL; ++ ++ while (*value) { ++ if (*value == '$') { ++ if (start != end) { ++ buffer = field_append(is_var, buffer, start, end); ++ if (!buffer) ++ return NULL; ++ } ++ ++ is_var = true; ++ start = value + 1; ++ } else if (is_var) { ++ if (!grub_isalnum(*value) && *value != '_') { ++ buffer = field_append(is_var, buffer, start, end); ++ is_var = false; ++ start = value; ++ if (*start == ' ') ++ start++; ++ } ++ } ++ ++ end = value; ++ value++; ++ } ++ ++ if (start != end) { ++ buffer = field_append(is_var, buffer, start, end); ++ if (!buffer) ++ return NULL; ++ } ++ ++ return buffer; ++} ++ ++static char **early_initrd_list (const char *initrd) ++{ ++ int nlist = 0; ++ char **list = NULL; ++ char *separator; ++ ++ while ((separator = grub_strchr (initrd, ' '))) ++ { ++ list = grub_realloc (list, (nlist + 2) * sizeof (char *)); ++ if (!list) ++ return NULL; ++ ++ list[nlist++] = grub_strndup(initrd, separator - initrd); ++ list[nlist] = NULL; ++ initrd = separator + 1; ++ } ++ ++ list = grub_realloc (list, (nlist + 2) * sizeof (char *)); ++ if (!list) ++ return NULL; ++ ++ list[nlist++] = grub_strndup(initrd, grub_strlen(initrd)); ++ list[nlist] = NULL; ++ ++ return list; ++} ++ ++static void create_entry (struct bls_entry *entry) ++{ ++ int argc = 0; ++ const char **argv = NULL; ++ ++ char *title = NULL; ++ char *clinux = NULL; ++ char *options = NULL; ++ char **initrds = NULL; ++ char *initrd = NULL; ++ const char *early_initrd = NULL; ++ char **early_initrds = NULL; ++ char *initrd_prefix = NULL; ++ char *devicetree = NULL; ++ char *dt = NULL; ++ char *id = entry->filename; ++ char *dotconf = id; ++ char *hotkey = NULL; ++ ++ char *users = NULL; ++ char **classes = NULL; ++ ++ char **args = NULL; ++ ++ char *src = NULL; ++ int i, index; ++ bool add_dt_prefix = false; ++ ++ grub_dprintf("blscfg", "%s got here\n", __func__); ++ clinux = bls_get_val (entry, "linux", NULL); ++ if (!clinux) ++ { ++ grub_dprintf ("blscfg", "Skipping file %s with no 'linux' key.\n", entry->filename); ++ goto finish; ++ } ++ ++ /* ++ * strip the ".conf" off the end before we make it our "id" field. ++ */ ++ do ++ { ++ dotconf = grub_strstr(dotconf, ".conf"); ++ } while (dotconf != NULL && dotconf[5] != '\0'); ++ if (dotconf) ++ dotconf[0] = '\0'; ++ ++ title = bls_get_val (entry, "title", NULL); ++ options = expand_val (bls_get_val (entry, "options", NULL)); ++ ++ if (!options) ++ options = expand_val (grub_env_get("default_kernelopts")); ++ ++ initrds = bls_make_list (entry, "initrd", NULL); ++ ++ devicetree = expand_val (bls_get_val (entry, "devicetree", NULL)); ++ ++ if (!devicetree) ++ { ++ devicetree = expand_val (grub_env_get("devicetree")); ++ add_dt_prefix = true; ++ } ++ ++ hotkey = bls_get_val (entry, "grub_hotkey", NULL); ++ users = expand_val (bls_get_val (entry, "grub_users", NULL)); ++ classes = bls_make_list (entry, "grub_class", NULL); ++ args = bls_make_list (entry, "grub_arg", &argc); ++ ++ argc += 1; ++ argv = grub_malloc ((argc + 1) * sizeof (char *)); ++ argv[0] = title ? title : clinux; ++ for (i = 1; i < argc; i++) ++ argv[i] = args[i-1]; ++ argv[argc] = NULL; ++ ++ early_initrd = grub_env_get("early_initrd"); ++ ++ grub_dprintf ("blscfg", "adding menu entry for \"%s\" with id \"%s\"\n", ++ title, id); ++ if (early_initrd) ++ { ++ early_initrds = early_initrd_list(early_initrd); ++ if (!early_initrds) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto finish; ++ } ++ ++ if (initrds != NULL && initrds[0] != NULL) ++ { ++ initrd_prefix = grub_strrchr (initrds[0], '/'); ++ initrd_prefix = grub_strndup(initrds[0], initrd_prefix - initrds[0] + 1); ++ } ++ else ++ { ++ initrd_prefix = grub_strrchr (clinux, '/'); ++ initrd_prefix = grub_strndup(clinux, initrd_prefix - clinux + 1); ++ } ++ ++ if (!initrd_prefix) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto finish; ++ } ++ } ++ ++ if (early_initrds || initrds) ++ { ++ int initrd_size = sizeof ("initrd"); ++ char *tmp; ++ ++ for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) ++ initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \ ++ + grub_strlen(initrd_prefix) \ ++ + grub_strlen (early_initrds[i]) + 1; ++ ++ for (i = 0; initrds != NULL && initrds[i] != NULL; i++) ++ initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \ ++ + grub_strlen (initrds[i]) + 1; ++ initrd_size += 1; ++ ++ initrd = grub_malloc (initrd_size); ++ if (!initrd) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto finish; ++ } ++ ++ tmp = grub_stpcpy(initrd, "initrd"); ++ for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) ++ { ++ grub_dprintf ("blscfg", "adding early initrd %s\n", early_initrds[i]); ++ tmp = frob_boot_device (tmp); ++ tmp = grub_stpcpy (tmp, initrd_prefix); ++ tmp = grub_stpcpy (tmp, early_initrds[i]); ++ grub_free(early_initrds[i]); ++ } ++ ++ for (i = 0; initrds != NULL && initrds[i] != NULL; i++) ++ { ++ grub_dprintf ("blscfg", "adding initrd %s\n", initrds[i]); ++ tmp = frob_boot_device (tmp); ++ tmp = grub_stpcpy (tmp, initrds[i]); ++ } ++ tmp = grub_stpcpy (tmp, "\n"); ++ } ++ ++ if (devicetree) ++ { ++ char *prefix = NULL; ++ int dt_size; ++ ++ if (add_dt_prefix) ++ { ++ prefix = grub_strrchr (clinux, '/'); ++ prefix = grub_strndup(clinux, prefix - clinux + 1); ++ if (!prefix) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto finish; ++ } ++ } ++ ++ dt_size = sizeof("devicetree " GRUB_BOOT_DEVICE) + grub_strlen(devicetree) + 1; ++ ++ if (add_dt_prefix) ++ { ++ dt_size += grub_strlen(prefix); ++ } ++ ++ dt = grub_malloc (dt_size); ++ if (!dt) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto finish; ++ } ++ char *tmp = dt; ++ tmp = grub_stpcpy (dt, "devicetree"); ++ tmp = frob_boot_device (tmp); ++ if (add_dt_prefix) ++ tmp = grub_stpcpy (tmp, prefix); ++ tmp = grub_stpcpy (tmp, devicetree); ++ tmp = grub_stpcpy (tmp, "\n"); ++ ++ grub_free(prefix); ++ } ++ ++ grub_dprintf ("blscfg2", "devicetree %s for id:\"%s\"\n", dt, id); ++ ++ const char *sdval = grub_env_get("save_default"); ++ bool savedefault = ((NULL != sdval) && (grub_strcmp(sdval, "true") == 0)); ++ src = grub_xasprintf ("%sload_video\n" ++ "set gfxpayload=keep\n" ++ "insmod gzio\n" ++ "linux %s%s%s%s\n" ++ "%s%s", ++ savedefault ? "savedefault\n" : "", ++ separate_boot ? GRUB_BOOT_DEVICE : "", ++ clinux, options ? " " : "", options ? options : "", ++ initrd ? initrd : "", dt ? dt : ""); ++ ++ grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, &index, entry); ++ grub_dprintf ("blscfg", "Added entry %d id:\"%s\"\n", index, id); ++ ++finish: ++ grub_free (dt); ++ grub_free (initrd); ++ grub_free (initrd_prefix); ++ grub_free (early_initrds); ++ grub_free (devicetree); ++ grub_free (initrds); ++ grub_free (options); ++ grub_free (classes); ++ grub_free (args); ++ grub_free (argv); ++ grub_free (src); ++} ++ ++struct find_entry_info { ++ const char *dirname; ++ const char *devid; ++ grub_device_t dev; ++ grub_fs_t fs; ++}; ++ ++/* ++ * info: the filesystem object the file is on. ++ */ ++static int find_entry (struct find_entry_info *info) ++{ ++ struct read_entry_info read_entry_info; ++ grub_fs_t blsdir_fs = NULL; ++ grub_device_t blsdir_dev = NULL; ++ const char *blsdir = info->dirname; ++ int fallback = 0; ++ int r = 0; ++ ++ if (!blsdir) { ++ blsdir = grub_env_get ("blsdir"); ++ if (!blsdir) ++ blsdir = GRUB_BLS_CONFIG_PATH; ++ } ++ ++ read_entry_info.file = NULL; ++ read_entry_info.dirname = blsdir; ++ ++ grub_dprintf ("blscfg", "scanning blsdir: %s\n", blsdir); ++ ++ blsdir_dev = info->dev; ++ blsdir_fs = info->fs; ++ read_entry_info.devid = info->devid; ++ ++read_fallback: ++ r = blsdir_fs->fs_dir (blsdir_dev, read_entry_info.dirname, read_entry, ++ &read_entry_info); ++ if (r != 0) { ++ grub_dprintf ("blscfg", "read_entry returned error\n"); ++ grub_err_t e; ++ do ++ { ++ e = grub_error_pop(); ++ } while (e); ++ } ++ ++ if (r && !info->dirname && !fallback) { ++ read_entry_info.dirname = "/boot" GRUB_BLS_CONFIG_PATH; ++ grub_dprintf ("blscfg", "Entries weren't found in %s, fallback to %s\n", ++ blsdir, read_entry_info.dirname); ++ fallback = 1; ++ goto read_fallback; ++ } ++ ++ return 0; ++} ++ ++static grub_err_t ++bls_load_entries (const char *path) ++{ ++ grub_size_t len; ++ grub_fs_t fs; ++ grub_device_t dev; ++ static grub_err_t r; ++ const char *devid = NULL; ++ char *blsdir = NULL; ++ struct find_entry_info info = { ++ .dev = NULL, ++ .fs = NULL, ++ .dirname = NULL, ++ }; ++ struct read_entry_info rei = { ++ .devid = NULL, ++ .dirname = NULL, ++ }; ++ ++ if (path) { ++ len = grub_strlen (path); ++ if (grub_strcmp (path + len - 5, ".conf") == 0) { ++ rei.file = grub_file_open (path, GRUB_FILE_TYPE_CONFIG); ++ if (!rei.file) ++ return grub_errno; ++ /* ++ * read_entry() closes the file ++ */ ++ return read_entry(path, NULL, &rei); ++ } else if (path[0] == '(') { ++ devid = path + 1; ++ ++ blsdir = grub_strchr (path, ')'); ++ if (!blsdir) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Filepath isn't correct")); ++ ++ *blsdir = '\0'; ++ blsdir = blsdir + 1; ++ } ++ } ++ ++ if (!devid) { ++#ifdef GRUB_MACHINE_EMU ++ devid = "host"; ++#else ++ devid = grub_env_get ("root"); ++#endif ++ if (!devid) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, ++ N_("variable `%s' isn't set"), "root"); ++ } ++ ++ grub_dprintf ("blscfg", "opening %s\n", devid); ++ dev = grub_device_open (devid); ++ if (!dev) ++ return grub_errno; ++ ++ grub_dprintf ("blscfg", "probing fs\n"); ++ fs = grub_fs_probe (dev); ++ if (!fs) ++ { ++ r = grub_errno; ++ goto finish; ++ } ++ ++ info.dirname = blsdir; ++ info.devid = devid; ++ info.dev = dev; ++ info.fs = fs; ++ find_entry(&info); ++ ++finish: ++ if (dev) ++ grub_device_close (dev); ++ ++ return r; ++} ++ ++static bool ++is_default_entry(const char *def_entry, struct bls_entry *entry, int idx) ++{ ++ const char *title; ++ int def_idx; ++ ++ if (!def_entry) ++ return false; ++ ++ if (grub_strcmp(def_entry, entry->filename) == 0) ++ return true; ++ ++ title = bls_get_val(entry, "title", NULL); ++ ++ if (title && grub_strcmp(def_entry, title) == 0) ++ return true; ++ ++ def_idx = (int)grub_strtol(def_entry, NULL, 0); ++ if (grub_errno == GRUB_ERR_BAD_NUMBER) { ++ grub_errno = GRUB_ERR_NONE; ++ return false; ++ } ++ ++ if (def_idx == idx) ++ return true; ++ ++ return false; ++} ++ ++static grub_err_t ++bls_create_entries (bool show_default, bool show_non_default, char *entry_id) ++{ ++ const char *def_entry = NULL; ++ struct bls_entry *entry = NULL; ++ int idx = 0; ++ ++ def_entry = grub_env_get("default"); ++ ++ grub_dprintf ("blscfg", "%s Creating entries from bls\n", __func__); ++ FOR_BLS_ENTRIES(entry) { ++ if (entry->visible) { ++ idx++; ++ continue; ++ } ++ ++ if ((show_default && is_default_entry(def_entry, entry, idx)) || ++ (show_non_default && !is_default_entry(def_entry, entry, idx)) || ++ (entry_id && grub_strcmp(entry_id, entry->filename) == 0)) { ++ create_entry(entry); ++ entry->visible = 1; ++ } ++ idx++; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED, ++ int argc, char **args) ++{ ++ grub_err_t r; ++ char *path = NULL; ++ char *entry_id = NULL; ++ bool show_default = true; ++ bool show_non_default = true; ++ ++ if (argc == 1) { ++ if (grub_strcmp (args[0], "default") == 0) { ++ show_non_default = false; ++ } else if (grub_strcmp (args[0], "non-default") == 0) { ++ show_default = false; ++ } else if (args[0][0] == '(') { ++ path = args[0]; ++ } else { ++ entry_id = args[0]; ++ show_default = false; ++ show_non_default = false; ++ } ++ } ++ ++ r = bls_load_entries(path); ++ if (r) ++ return r; ++ ++ return bls_create_entries(show_default, show_non_default, entry_id); ++} ++ ++static grub_extcmd_t cmd; ++static grub_extcmd_t oldcmd; ++ ++GRUB_MOD_INIT(blscfg) ++{ ++ grub_dprintf("blscfg", "%s got here\n", __func__); ++ cmd = grub_register_extcmd ("blscfg", ++ grub_cmd_blscfg, ++ 0, ++ NULL, ++ N_("Import Boot Loader Specification snippets."), ++ NULL); ++ oldcmd = grub_register_extcmd ("bls_import", ++ grub_cmd_blscfg, ++ 0, ++ NULL, ++ N_("Import Boot Loader Specification snippets."), ++ NULL); ++} ++ ++GRUB_MOD_FINI(blscfg) ++{ ++ grub_unregister_extcmd (cmd); ++ grub_unregister_extcmd (oldcmd); ++} +diff --git a/grub-core/commands/efi/connectefi.c b/grub-core/commands/efi/connectefi.c +new file mode 100644 +index 000000000..9d02f2780 +--- /dev/null ++++ b/grub-core/commands/efi/connectefi.c +@@ -0,0 +1,205 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++typedef struct handle_list ++{ ++ grub_efi_handle_t handle; ++ struct handle_list *next; ++} handle_list_t; ++ ++static handle_list_t *already_handled = NULL; ++ ++static grub_err_t ++add_handle (grub_efi_handle_t handle) ++{ ++ handle_list_t *e; ++ e = grub_malloc (sizeof (*e)); ++ if (! e) ++ return grub_errno; ++ e->handle = handle; ++ e->next = already_handled; ++ already_handled = e; ++ return GRUB_ERR_NONE; ++} ++ ++static int ++is_in_list (grub_efi_handle_t handle) ++{ ++ handle_list_t *e; ++ for (e = already_handled; e != NULL; e = e->next) ++ if (e->handle == handle) ++ return 1; ++ return 0; ++} ++ ++static void ++free_handle_list (void) ++{ ++ handle_list_t *e; ++ while ((e = already_handled) != NULL) ++ { ++ already_handled = already_handled->next; ++ grub_free (e); ++ } ++} ++ ++typedef enum searched_item_flag ++{ ++ SEARCHED_ITEM_FLAG_LOOP = 1, ++ SEARCHED_ITEM_FLAG_RECURSIVE = 2 ++} searched_item_flags; ++ ++typedef struct searched_item ++{ ++ grub_guid_t guid; ++ const char *name; ++ searched_item_flags flags; ++} searched_items; ++ ++static grub_err_t ++grub_cmd_connectefi (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char **args) ++{ ++ unsigned s; ++ searched_items pciroot_items[] = ++ { ++ { GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root", SEARCHED_ITEM_FLAG_RECURSIVE } ++ }; ++ searched_items scsi_items[] = ++ { ++ { GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root", 0 }, ++ { GRUB_EFI_PCI_IO_GUID, "PCI", SEARCHED_ITEM_FLAG_LOOP }, ++ { GRUB_EFI_SCSI_IO_PROTOCOL_GUID, "SCSI I/O", SEARCHED_ITEM_FLAG_RECURSIVE } ++ }; ++ searched_items *items = NULL; ++ unsigned nitems = 0; ++ grub_err_t grub_err = GRUB_ERR_NONE; ++ unsigned total_connected = 0; ++ ++ if (argc != 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); ++ ++ if (grub_strcmp(args[0], N_("pciroot")) == 0) ++ { ++ items = pciroot_items; ++ nitems = ARRAY_SIZE (pciroot_items); ++ } ++ else if (grub_strcmp(args[0], N_("scsi")) == 0) ++ { ++ items = scsi_items; ++ nitems = ARRAY_SIZE (scsi_items); ++ } ++ else ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("unexpected argument `%s'"), args[0]); ++ ++ for (s = 0; s < nitems; s++) ++ { ++ grub_efi_handle_t *handles; ++ grub_efi_uintn_t num_handles; ++ unsigned i, connected = 0, loop = 0; ++ ++loop: ++ loop++; ++ grub_dprintf ("efi", "step '%s' loop %d:\n", items[s].name, loop); ++ ++ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, ++ &items[s].guid, 0, &num_handles); ++ ++ if (!handles) ++ continue; ++ ++ for (i = 0; i < num_handles; i++) ++ { ++ grub_efi_handle_t handle = handles[i]; ++ grub_efi_status_t status; ++ ++ /* Skip already handled handles */ ++ if (is_in_list (handle)) ++ { ++ grub_dprintf ("efi", " handle %p: already processed\n", ++ handle); ++ continue; ++ } ++ ++ status = grub_efi_connect_controller(handle, NULL, NULL, ++ items[s].flags & SEARCHED_ITEM_FLAG_RECURSIVE ? 1 : 0); ++ if (status == GRUB_EFI_SUCCESS) ++ { ++ connected++; ++ total_connected++; ++ grub_dprintf ("efi", " handle %p: connected\n", handle); ++ } ++ else ++ grub_dprintf ("efi", " handle %p: failed to connect (%d)\n", ++ handle, (grub_efi_int8_t) status); ++ ++ if ((grub_err = add_handle (handle)) != GRUB_ERR_NONE) ++ break; /* fatal */ ++ } ++ ++ grub_free (handles); ++ if (grub_err != GRUB_ERR_NONE) ++ break; /* fatal */ ++ ++ if (items[s].flags & SEARCHED_ITEM_FLAG_LOOP && connected) ++ { ++ connected = 0; ++ goto loop; ++ } ++ ++ free_handle_list (); ++ } ++ ++ free_handle_list (); ++ ++ if (total_connected) ++ grub_efidisk_reenumerate_disks (); ++ ++ return grub_err; ++} ++ ++static grub_command_t cmd; ++ ++GRUB_MOD_INIT(connectefi) ++{ ++ cmd = grub_register_command ("connectefi", grub_cmd_connectefi, ++ N_("pciroot|scsi"), ++ N_("Connect EFI handles." ++ " If 'pciroot' is specified, connect PCI" ++ " root EFI handles recursively." ++ " If 'scsi' is specified, connect SCSI" ++ " I/O EFI handles recursively.")); ++} ++ ++GRUB_MOD_FINI(connectefi) ++{ ++ grub_unregister_command (cmd); ++} +diff --git a/grub-core/commands/efi/env.c b/grub-core/commands/efi/env.c +new file mode 100644 +index 000000000..4080f24fd +--- /dev/null ++++ b/grub-core/commands/efi/env.c +@@ -0,0 +1,170 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2012 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static const grub_guid_t grub_env_guid = GRUB_EFI_GRUB_VARIABLE_GUID; ++ ++static grub_err_t ++grub_efi_export_env(grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ const char *value; ++ char *old_value; ++ struct grub_envblk envblk_s = { NULL, 0 }; ++ grub_envblk_t envblk = &envblk_s; ++ grub_err_t err; ++ int changed = 1; ++ grub_efi_status_t status; ++ ++ grub_dprintf ("efienv", "argc:%d\n", argc); ++ for (int i = 0; i < argc; i++) ++ grub_dprintf ("efienv", "argv[%d]: %s\n", i, argv[i]); ++ ++ if (argc != 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("variable name expected")); ++ ++ grub_efi_get_variable ("GRUB_ENV", &grub_env_guid, &envblk_s.size, ++ (void **) &envblk_s.buf); ++ if (!envblk_s.buf || envblk_s.size < 1) ++ { ++ char *buf = grub_malloc (1025); ++ if (!buf) ++ return grub_errno; ++ ++ grub_memcpy (buf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1); ++ grub_memset (buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1, '#', ++ DEFAULT_ENVBLK_SIZE - sizeof (GRUB_ENVBLK_SIGNATURE) + 1); ++ buf[1024] = '\0'; ++ ++ envblk_s.buf = buf; ++ envblk_s.size = 1024; ++ } ++ else ++ { ++ char *buf = grub_realloc (envblk_s.buf, envblk_s.size + 1); ++ if (!buf) ++ return grub_errno; ++ ++ envblk_s.buf = buf; ++ envblk_s.buf[envblk_s.size] = '\0'; ++ } ++ ++ err = grub_envblk_get(envblk, argv[0], &old_value); ++ if (err != GRUB_ERR_NONE) ++ { ++ grub_dprintf ("efienv", "grub_envblk_get returned %d\n", err); ++ return err; ++ } ++ ++ value = grub_env_get(argv[0]); ++ if ((!value && !old_value) || ++ (value && old_value && !grub_strcmp(old_value, value))) ++ changed = 0; ++ ++ if (old_value) ++ grub_free(old_value); ++ ++ if (changed == 0) ++ { ++ grub_dprintf ("efienv", "No changes necessary\n"); ++ return 0; ++ } ++ ++ if (value) ++ { ++ grub_dprintf ("efienv", "setting \"%s\" to \"%s\"\n", argv[0], value); ++ grub_envblk_set(envblk, argv[0], value); ++ } ++ else ++ { ++ grub_dprintf ("efienv", "deleting \"%s\" from envblk\n", argv[0]); ++ grub_envblk_delete(envblk, argv[0]); ++ } ++ ++ grub_dprintf ("efienv", "envblk is %lu bytes:\n\"%s\"\n", envblk_s.size, envblk_s.buf); ++ ++ grub_dprintf ("efienv", "removing GRUB_ENV\n"); ++ status = grub_efi_set_variable ("GRUB_ENV", &grub_env_guid, NULL, 0); ++ if (status != GRUB_EFI_SUCCESS) ++ grub_dprintf ("efienv", "removal returned %ld\n", status); ++ ++ grub_dprintf ("efienv", "setting GRUB_ENV\n"); ++ status = grub_efi_set_variable ("GRUB_ENV", &grub_env_guid, ++ envblk_s.buf, envblk_s.size); ++ if (status != GRUB_EFI_SUCCESS) ++ grub_dprintf ("efienv", "setting GRUB_ENV returned %ld\n", status); ++ ++ return 0; ++} ++ ++static int ++set_var (const char *name, const char *value, ++ void *whitelist __attribute__((__unused__))) ++{ ++ grub_env_set (name, value); ++ return 0; ++} ++ ++static grub_err_t ++grub_efi_load_env(grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[] __attribute__((__unused__))) ++{ ++ struct grub_envblk envblk_s = { NULL, 0 }; ++ grub_envblk_t envblk = &envblk_s; ++ ++ grub_efi_get_variable ("GRUB_ENV", &grub_env_guid, &envblk_s.size, ++ (void **) &envblk_s.buf); ++ if (!envblk_s.buf || envblk_s.size < 1) ++ return 0; ++ ++ if (argc > 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unexpected argument")); ++ ++ grub_envblk_iterate (envblk, NULL, set_var); ++ grub_free (envblk_s.buf); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_command_t export_cmd, loadenv_cmd; ++ ++GRUB_MOD_INIT(lsefi) ++{ ++ export_cmd = grub_register_command ("efi-export-env", grub_efi_export_env, ++ N_("VARIABLE_NAME"), N_("Export environment variable to UEFI.")); ++ loadenv_cmd = grub_register_command ("efi-load-env", grub_efi_load_env, ++ NULL, N_("Load the grub environment from UEFI.")); ++} ++ ++GRUB_MOD_FINI(lsefi) ++{ ++ grub_unregister_command (export_cmd); ++ grub_unregister_command (loadenv_cmd); ++} +diff --git a/grub-core/commands/efi/lsefi.c b/grub-core/commands/efi/lsefi.c +index 7b8316d41..3635cd99b 100644 +--- a/grub-core/commands/efi/lsefi.c ++++ b/grub-core/commands/efi/lsefi.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/grub-core/commands/increment.c b/grub-core/commands/increment.c +new file mode 100644 +index 000000000..79cf13765 +--- /dev/null ++++ b/grub-core/commands/increment.c +@@ -0,0 +1,105 @@ ++/* increment.c - Commands to increment and decrement variables. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++typedef enum { ++ INCREMENT, ++ DECREMENT, ++} operation; ++ ++static grub_err_t ++incr_decr(operation op, int argc, char **args) ++{ ++ const char *old; ++ char *new; ++ long value; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("no variable specified")); ++ if (argc > 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("too many arguments")); ++ ++ old = grub_env_get (*args); ++ if (!old) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("No such variable \"%s\""), ++ *args); ++ ++ value = grub_strtol (old, NULL, 0); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ switch (op) ++ { ++ case INCREMENT: ++ value += 1; ++ break; ++ case DECREMENT: ++ value -= 1; ++ break; ++ } ++ ++ new = grub_xasprintf ("%ld", value); ++ if (!new) ++ return grub_errno; ++ ++ grub_env_set (*args, new); ++ grub_free (new); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_incr(struct grub_command *cmd UNUSED, ++ int argc, char **args) ++{ ++ return incr_decr(INCREMENT, argc, args); ++} ++ ++static grub_err_t ++grub_cmd_decr(struct grub_command *cmd UNUSED, ++ int argc, char **args) ++{ ++ return incr_decr(DECREMENT, argc, args); ++} ++ ++static grub_command_t cmd_incr, cmd_decr; ++ ++GRUB_MOD_INIT(increment) ++{ ++ cmd_incr = grub_register_command ("increment", grub_cmd_incr, N_("VARIABLE"), ++ N_("increment VARIABLE")); ++ cmd_decr = grub_register_command ("decrement", grub_cmd_decr, N_("VARIABLE"), ++ N_("decrement VARIABLE")); ++} ++ ++GRUB_MOD_FINI(increment) ++{ ++ grub_unregister_command (cmd_incr); ++ grub_unregister_command (cmd_decr); ++} +diff --git a/grub-core/commands/iorw.c b/grub-core/commands/iorw.c +index 584baec8f..7b2999b14 100644 +--- a/grub-core/commands/iorw.c ++++ b/grub-core/commands/iorw.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -119,6 +120,9 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv) + + GRUB_MOD_INIT(memrw) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + cmd_read_byte = + grub_register_extcmd ("inb", grub_cmd_read, 0, + N_("PORT"), N_("Read 8-bit value from PORT."), +@@ -147,6 +151,9 @@ GRUB_MOD_INIT(memrw) + + GRUB_MOD_FINI(memrw) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + grub_unregister_extcmd (cmd_read_byte); + grub_unregister_extcmd (cmd_read_word); + grub_unregister_extcmd (cmd_read_dword); +diff --git a/grub-core/commands/legacycfg.c b/grub-core/commands/legacycfg.c +index e9e9d94ef..2c5d1a0ef 100644 +--- a/grub-core/commands/legacycfg.c ++++ b/grub-core/commands/legacycfg.c +@@ -143,7 +143,7 @@ legacy_file (const char *filename) + args[0] = oldname; + grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy", + NULL, NULL, +- entrysrc, 0); ++ entrysrc, 0, NULL, NULL); + grub_free (args); + entrysrc[0] = 0; + grub_free (oldname); +@@ -205,7 +205,8 @@ legacy_file (const char *filename) + } + args[0] = entryname; + grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, +- NULL, NULL, entrysrc, 0); ++ NULL, NULL, entrysrc, 0, NULL, ++ NULL); + grub_free (args); + } + +diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c +index 166445849..dfcb19e0f 100644 +--- a/grub-core/commands/loadenv.c ++++ b/grub-core/commands/loadenv.c +@@ -28,6 +28,8 @@ + #include + #include + ++#include "loadenv.h" ++ + GRUB_MOD_LICENSE ("GPLv3+"); + + static const struct grub_arg_option options[] = +@@ -79,81 +81,6 @@ open_envblk_file (char *filename, + return file; + } + +-static grub_envblk_t +-read_envblk_file (grub_file_t file) +-{ +- grub_off_t offset = 0; +- char *buf; +- grub_size_t size = grub_file_size (file); +- grub_envblk_t envblk; +- +- buf = grub_malloc (size); +- if (! buf) +- return 0; +- +- while (size > 0) +- { +- grub_ssize_t ret; +- +- ret = grub_file_read (file, buf + offset, size); +- if (ret <= 0) +- { +- grub_free (buf); +- return 0; +- } +- +- size -= ret; +- offset += ret; +- } +- +- envblk = grub_envblk_open (buf, offset); +- if (! envblk) +- { +- grub_free (buf); +- grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block"); +- return 0; +- } +- +- return envblk; +-} +- +-struct grub_env_whitelist +-{ +- grub_size_t len; +- char **list; +-}; +-typedef struct grub_env_whitelist grub_env_whitelist_t; +- +-static int +-test_whitelist_membership (const char* name, +- const grub_env_whitelist_t* whitelist) +-{ +- grub_size_t i; +- +- for (i = 0; i < whitelist->len; i++) +- if (grub_strcmp (name, whitelist->list[i]) == 0) +- return 1; /* found it */ +- +- return 0; /* not found */ +-} +- +-/* Helper for grub_cmd_load_env. */ +-static int +-set_var (const char *name, const char *value, void *whitelist) +-{ +- if (! whitelist) +- { +- grub_env_set (name, value); +- return 0; +- } +- +- if (test_whitelist_membership (name, +- (const grub_env_whitelist_t *) whitelist)) +- grub_env_set (name, value); +- +- return 0; +-} +- + static grub_err_t + grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc, char **args) + { +diff --git a/grub-core/commands/loadenv.h b/grub-core/commands/loadenv.h +new file mode 100644 +index 000000000..952f46121 +--- /dev/null ++++ b/grub-core/commands/loadenv.h +@@ -0,0 +1,93 @@ ++/* loadenv.c - command to load/save environment variable. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++static grub_envblk_t UNUSED ++read_envblk_file (grub_file_t file) ++{ ++ grub_off_t offset = 0; ++ char *buf; ++ grub_size_t size = grub_file_size (file); ++ grub_envblk_t envblk; ++ ++ buf = grub_malloc (size); ++ if (! buf) ++ return 0; ++ ++ while (size > 0) ++ { ++ grub_ssize_t ret; ++ ++ ret = grub_file_read (file, buf + offset, size); ++ if (ret <= 0) ++ { ++ grub_free (buf); ++ return 0; ++ } ++ ++ size -= ret; ++ offset += ret; ++ } ++ ++ envblk = grub_envblk_open (buf, offset); ++ if (! envblk) ++ { ++ grub_free (buf); ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block"); ++ return 0; ++ } ++ ++ return envblk; ++} ++ ++struct grub_env_whitelist ++{ ++ grub_size_t len; ++ char **list; ++}; ++typedef struct grub_env_whitelist grub_env_whitelist_t; ++ ++static int UNUSED ++test_whitelist_membership (const char* name, ++ const grub_env_whitelist_t* whitelist) ++{ ++ grub_size_t i; ++ ++ for (i = 0; i < whitelist->len; i++) ++ if (grub_strcmp (name, whitelist->list[i]) == 0) ++ return 1; /* found it */ ++ ++ return 0; /* not found */ ++} ++ ++/* Helper for grub_cmd_load_env. */ ++static int UNUSED ++set_var (const char *name, const char *value, void *whitelist) ++{ ++ if (! whitelist) ++ { ++ grub_env_set (name, value); ++ return 0; ++ } ++ ++ if (test_whitelist_membership (name, ++ (const grub_env_whitelist_t *) whitelist)) ++ grub_env_set (name, value); ++ ++ return 0; ++} +diff --git a/grub-core/commands/memrw.c b/grub-core/commands/memrw.c +index d401a6db0..39cf3a06d 100644 +--- a/grub-core/commands/memrw.c ++++ b/grub-core/commands/memrw.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -121,6 +122,9 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv) + + GRUB_MOD_INIT(memrw) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + cmd_read_byte = + grub_register_extcmd ("read_byte", grub_cmd_read, 0, + N_("ADDR"), N_("Read 8-bit value from ADDR."), +@@ -149,6 +153,9 @@ GRUB_MOD_INIT(memrw) + + GRUB_MOD_FINI(memrw) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + grub_unregister_extcmd (cmd_read_byte); + grub_unregister_extcmd (cmd_read_word); + grub_unregister_extcmd (cmd_read_dword); +diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c +index 720e6d8ea..b175a1b43 100644 +--- a/grub-core/commands/menuentry.c ++++ b/grub-core/commands/menuentry.c +@@ -29,7 +29,7 @@ static const struct grub_arg_option options[] = + { + {"class", 1, GRUB_ARG_OPTION_REPEATABLE, + N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING}, +- {"users", 2, 0, ++ {"users", 2, GRUB_ARG_OPTION_OPTIONAL, + N_("List of users allowed to boot this entry."), N_("USERNAME[,USERNAME]"), + ARG_TYPE_STRING}, + {"hotkey", 3, 0, +@@ -78,7 +78,7 @@ grub_normal_add_menu_entry (int argc, const char **args, + char **classes, const char *id, + const char *users, const char *hotkey, + const char *prefix, const char *sourcecode, +- int submenu) ++ int submenu, int *index, struct bls_entry *bls) + { + int menu_hotkey = 0; + char **menu_args = NULL; +@@ -149,9 +149,12 @@ grub_normal_add_menu_entry (int argc, const char **args, + if (! menu_title) + goto fail; + ++ grub_dprintf ("menu", "id:\"%s\"\n", id); ++ grub_dprintf ("menu", "title:\"%s\"\n", menu_title); + menu_id = grub_strdup (id ? : menu_title); + if (! menu_id) + goto fail; ++ grub_dprintf ("menu", "menu_id:\"%s\"\n", menu_id); + + /* Save argc, args to pass as parameters to block arg later. */ + menu_args = grub_calloc (argc + 1, sizeof (char *)); +@@ -170,8 +173,12 @@ grub_normal_add_menu_entry (int argc, const char **args, + } + + /* Add the menu entry at the end of the list. */ ++ int ind=0; + while (*last) +- last = &(*last)->next; ++ { ++ ind++; ++ last = &(*last)->next; ++ } + + *last = grub_zalloc (sizeof (**last)); + if (! *last) +@@ -188,8 +195,11 @@ grub_normal_add_menu_entry (int argc, const char **args, + (*last)->args = menu_args; + (*last)->sourcecode = menu_sourcecode; + (*last)->submenu = submenu; ++ (*last)->bls = bls; + + menu->size++; ++ if (index) ++ *index = ind; + return GRUB_ERR_NONE; + + fail: +@@ -271,7 +281,7 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) + if (! ctxt->state[3].set && ! ctxt->script) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition"); + +- if (ctxt->state[1].set) ++ if (ctxt->state[1].set && ctxt->state[1].arg) + users = ctxt->state[1].arg; + else if (ctxt->state[5].set) + users = NULL; +@@ -286,7 +296,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) + users, + ctxt->state[2].arg, 0, + ctxt->state[3].arg, +- ctxt->extcmd->cmd->name[0] == 's'); ++ ctxt->extcmd->cmd->name[0] == 's', ++ NULL, NULL); + + src = args[argc - 1]; + args[argc - 1] = NULL; +@@ -303,7 +314,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) + ctxt->state[0].args, ctxt->state[4].arg, + users, + ctxt->state[2].arg, prefix, src + 1, +- ctxt->extcmd->cmd->name[0] == 's'); ++ ctxt->extcmd->cmd->name[0] == 's', NULL, ++ NULL); + + src[len - 1] = ch; + args[argc - 1] = src; +diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c +index fa498931e..2bd3ac76f 100644 +--- a/grub-core/commands/minicmd.c ++++ b/grub-core/commands/minicmd.c +@@ -182,12 +182,24 @@ grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)), + } + + /* exit */ +-static grub_err_t __attribute__ ((noreturn)) ++static grub_err_t + grub_mini_cmd_exit (struct grub_command *cmd __attribute__ ((unused)), +- int argc __attribute__ ((unused)), +- char *argv[] __attribute__ ((unused))) ++ int argc, char *argv[]) + { +- grub_exit (); ++ int retval = -1; ++ unsigned long n; ++ ++ if (argc < 0 || argc > 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); ++ ++ if (argc == 1) ++ { ++ n = grub_strtoul (argv[0], 0, 10); ++ if (n != ~0UL) ++ retval = n; ++ } ++ ++ grub_exit (retval); + /* Not reached. */ + } + +diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c +index c6766f044..847a5046a 100644 +--- a/grub-core/commands/pgp.c ++++ b/grub-core/commands/pgp.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -146,10 +147,6 @@ const char *hashes[] = { + [0x0b] = "sha224" + }; + +-struct gcry_pk_spec *grub_crypto_pk_dsa; +-struct gcry_pk_spec *grub_crypto_pk_ecdsa; +-struct gcry_pk_spec *grub_crypto_pk_rsa; +- + static int + dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval, + const gcry_md_spec_t *hash, struct grub_public_subkey *sk); +@@ -411,32 +408,7 @@ static int + rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval, + const gcry_md_spec_t *hash, struct grub_public_subkey *sk) + { +- grub_size_t tlen, emlen, fflen; +- grub_uint8_t *em, *emptr; +- unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]); +- int ret; +- tlen = hash->mdlen + hash->asnlen; +- emlen = (nbits + 7) / 8; +- if (emlen < tlen + 11) +- return 1; +- +- em = grub_malloc (emlen); +- if (!em) +- return 1; +- +- em[0] = 0x00; +- em[1] = 0x01; +- fflen = emlen - tlen - 3; +- for (emptr = em + 2; emptr < em + 2 + fflen; emptr++) +- *emptr = 0xff; +- *emptr++ = 0x00; +- grub_memcpy (emptr, hash->asnoid, hash->asnlen); +- emptr += hash->asnlen; +- grub_memcpy (emptr, hval, hash->mdlen); +- +- ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0); +- grub_free (em); +- return ret; ++ return grub_crypto_rsa_pad(hmpi, hval, hash, sk->mpis[0]); + } + + struct grub_pubkey_context +@@ -972,7 +944,7 @@ GRUB_MOD_INIT(pgp) + grub_memset (&pseudo_file, 0, sizeof (pseudo_file)); + + /* Not an ELF module, skip. */ +- if (header->type != OBJ_TYPE_PUBKEY) ++ if (header->type != OBJ_TYPE_GPG_PUBKEY) + continue; + + pseudo_file.fs = &pseudo_fs; +diff --git a/grub-core/commands/reboot.c b/grub-core/commands/reboot.c +index 46d364c99..f5cc22836 100644 +--- a/grub-core/commands/reboot.c ++++ b/grub-core/commands/reboot.c +@@ -32,15 +32,18 @@ grub_cmd_reboot (grub_command_t cmd __attribute__ ((unused)), + grub_reboot (); + } + +-static grub_command_t cmd; ++static grub_command_t reboot_cmd, reset_cmd; + + GRUB_MOD_INIT(reboot) + { +- cmd = grub_register_command ("reboot", grub_cmd_reboot, +- 0, N_("Reboot the computer.")); ++ reboot_cmd = grub_register_command ("reboot", grub_cmd_reboot, ++ 0, N_("Reboot the computer.")); ++ reset_cmd = grub_register_command ("reset", grub_cmd_reboot, ++ 0, N_("Reboot the computer.")); + } + + GRUB_MOD_FINI(reboot) + { +- grub_unregister_command (cmd); ++ grub_unregister_command (reboot_cmd); ++ grub_unregister_command (reset_cmd); + } +diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c +index 263f1501c..d538b3621 100644 +--- a/grub-core/commands/search.c ++++ b/grub-core/commands/search.c +@@ -30,6 +30,8 @@ + #include + #include + #include ++#include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -54,6 +56,100 @@ struct search_ctx + int is_cache; + }; + ++static int ++is_device_usb (const char *name) ++{ ++ int ret = 0; ++ ++ grub_device_t dev = grub_device_open(name); ++ ++ if (dev) ++ { ++ struct grub_efidisk_data ++ { ++ grub_efi_handle_t handle; ++ grub_efi_device_path_t *device_path; ++ grub_efi_device_path_t *last_device_path; ++ grub_efi_block_io_t *block_io; ++ struct grub_efidisk_data *next; ++ }; ++ ++ if (dev->disk && dev->disk->data) ++ { ++ struct grub_efidisk_data *dp = dev->disk->data; ++ ++ if ( GRUB_EFI_DEVICE_PATH_TYPE (dp->last_device_path) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE && ++ GRUB_EFI_DEVICE_PATH_SUBTYPE (dp->last_device_path) == GRUB_EFI_USB_DEVICE_PATH_SUBTYPE) ++ { ++ ret = 1; ++ } ++ } ++ grub_device_close(dev); ++ } ++ ++ return ret; ++} ++ ++static int ++get_device_uuid(const char *name, char** quid) ++{ ++ int ret = 0; ++ ++ grub_device_t dev_part = grub_device_open(name); ++ ++ if (dev_part) ++ { ++ grub_fs_t fs; ++ ++ fs = grub_fs_probe (dev_part); ++ ++#ifdef DO_SEARCH_FS_UUID ++#define read_fn fs_uuid ++#else ++#define read_fn fs_label ++#endif ++ if (fs && fs->read_fn) ++ { ++ fs->read_fn (dev_part, quid); ++ ++ if (grub_errno == GRUB_ERR_NONE && *quid) ++ { ++ ret = 1; ++ } ++ ++ } ++ grub_device_close (dev_part); ++ } ++ ++ return ret; ++} ++struct uuid_context { ++ char* name; ++ char* uuid; ++}; ++ ++static int ++check_for_duplicate (const char *name, void *data) ++{ ++ int ret = 0; ++ struct uuid_context * uuid_ctx = (struct uuid_context *)data; ++ char *quid = 0; ++ ++ get_device_uuid(name, &quid); ++ ++ if (quid == NULL) ++ return 0; ++ ++ if (!grub_strcasecmp(quid, uuid_ctx->uuid) && grub_strcasecmp(name, uuid_ctx->name)) ++ { ++ ret = 1; ++ } ++ ++ grub_free(quid); ++ ++ return ret; ++} ++ + /* Helper for FUNC_NAME. */ + static int + iterate_device (const char *name, void *data) +@@ -86,6 +182,66 @@ iterate_device (const char *name, void *data) + grub_device_close (dev); + } + ++ /* Skip it if it's not the root device when requested. */ ++ if (ctx->flags & SEARCH_FLAGS_ROOTDEV_ONLY) ++ { ++ const char *root_dev; ++ root_dev = grub_env_get ("root"); ++ if (root_dev != NULL && *root_dev != '\0') ++ { ++ char *root_disk = grub_malloc (grub_strlen(root_dev) + 1); ++ char *name_disk = grub_malloc (grub_strlen(name) + 1); ++ char *rem_1 = grub_malloc(grub_strlen(root_dev) + 1); ++ char *rem_2 = grub_malloc(grub_strlen(name) + 1); ++ ++ if (root_disk != NULL && name_disk != NULL && ++ rem_1 != NULL && rem_2 != NULL) ++ { ++ /* get just the disk name; partitions will be different. */ ++ grub_str_sep (root_dev, root_disk, ',', rem_1); ++ grub_str_sep (name, name_disk, ',', rem_2); ++ if (root_disk != NULL && *root_disk != '\0' && ++ name_disk != NULL && *name_disk != '\0') ++ { ++ grub_device_t dev, dev_part; ++ ++ if (is_device_usb(name) && !is_device_usb(root_dev)) ++ { ++ char *quid_name = NULL; ++ int longlist = 0; ++ struct uuid_context uuid_ctx; ++ int ret = 0; ++ ++ if (get_device_uuid(name, &quid_name)) ++ { ++ if (!grub_strcmp(quid_name, ctx->key)) ++ { ++ uuid_ctx.name = name; ++ uuid_ctx.uuid = quid_name; ++ ++ ret = grub_device_iterate (check_for_duplicate, &uuid_ctx); ++ ++ if (ret) ++ { ++ grub_printf("Duplicated media UUID found, rebooting ...\n"); ++ grub_sleep(10); ++ grub_reboot(); ++ } ++ } ++ ++ if (quid_name) grub_free (quid_name); ++ ++ } ++ } ++ } ++ } ++ grub_free (root_disk); ++ grub_free (name_disk); ++ grub_free (rem_1); ++ grub_free (rem_2); ++ } ++ } ++ + #ifdef DO_SEARCH_FS_UUID + #define compare_fn grub_strcasecmp + #else +diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c +index 318581f3b..4fe6440c6 100644 +--- a/grub-core/commands/search_wrap.c ++++ b/grub-core/commands/search_wrap.c +@@ -41,6 +41,7 @@ static const struct grub_arg_option options[] = + ARG_TYPE_STRING}, + {"no-floppy", 'n', 0, N_("Do not probe any floppy drive."), 0, 0}, + {"efidisk-only", 0, 0, N_("Only probe EFI disks."), 0, 0}, ++ {"root-dev-only", 'r', 0, N_("Only probe root device."), 0, 0}, + {"hint", 'h', GRUB_ARG_OPTION_REPEATABLE, + N_("First try the device HINT. If HINT ends in comma, " + "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING}, +@@ -75,6 +76,7 @@ enum options + SEARCH_SET, + SEARCH_NO_FLOPPY, + SEARCH_EFIDISK_ONLY, ++ SEARCH_ROOTDEV_ONLY, + SEARCH_HINT, + SEARCH_HINT_IEEE1275, + SEARCH_HINT_BIOS, +@@ -189,6 +191,9 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) + if (state[SEARCH_EFIDISK_ONLY].set) + flags |= SEARCH_FLAGS_EFIDISK_ONLY; + ++ if (state[SEARCH_ROOTDEV_ONLY].set) ++ flags |= SEARCH_FLAGS_ROOTDEV_ONLY; ++ + if (state[SEARCH_LABEL].set) + grub_search_label (id, var, flags, hints, nhints); + else if (state[SEARCH_FS_UUID].set) +diff --git a/grub-core/commands/version.c b/grub-core/commands/version.c +new file mode 100644 +index 000000000..de0acb07b +--- /dev/null ++++ b/grub-core/commands/version.c +@@ -0,0 +1,56 @@ ++/* version.c - Command to print the grub version and build info. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_err_t ++grub_cmd_version (grub_command_t cmd UNUSED, int argc, char **args UNUSED) ++{ ++ if (argc != 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("no arguments expected")); ++ ++ grub_printf (_("GRUB version %s\n"), PACKAGE_VERSION); ++ grub_printf (_("Platform %s-%s\n"), GRUB_TARGET_CPU, GRUB_PLATFORM); ++ if (grub_strlen(GRUB_RPM_VERSION) != 0) ++ grub_printf (_("RPM package version %s\n"), GRUB_RPM_VERSION); ++ grub_printf (_("Compiler version %s\n"), __VERSION__); ++ ++ return 0; ++} ++ ++static grub_command_t cmd; ++ ++GRUB_MOD_INIT(version) ++{ ++ cmd = grub_register_command ("version", grub_cmd_version, NULL, ++ N_("Print version and build information.")); ++} ++ ++GRUB_MOD_FINI(version) ++{ ++ grub_unregister_command (cmd); ++} +diff --git a/grub-core/commands/wildcard.c b/grub-core/commands/wildcard.c +index ed6586505..5455242c3 100644 +--- a/grub-core/commands/wildcard.c ++++ b/grub-core/commands/wildcard.c +@@ -488,6 +488,12 @@ check_file (const char *dir, const char *basename) + return ctx.found; + } + ++static int ++is_hex(char c) ++{ ++ return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); ++} ++ + static void + unescape (char *out, const char *in, const char *end) + { +@@ -496,7 +502,15 @@ unescape (char *out, const char *in, const char *end) + + for (optr = out, iptr = in; iptr < end;) + { +- if (*iptr == '\\' && iptr + 1 < end) ++ if (*iptr == '\\' && iptr + 3 < end && iptr[1] == 'x' && is_hex(iptr[2]) && is_hex(iptr[3])) ++ { ++ *optr++ = *iptr++; ++ *optr++ = *iptr++; ++ *optr++ = *iptr++; ++ *optr++ = *iptr++; ++ continue; ++ } ++ else if (*iptr == '\\' && iptr + 1 < end) + { + *optr++ = iptr[1]; + iptr += 2; +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 2246af51b..98e176a13 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -721,7 +721,7 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk) + #ifdef GRUB_UTIL + if (dev->cheat) + { +- grub_uint64_t cheat_dev_size; ++ grub_int64_t cheat_dev_size; + unsigned int cheat_log_sector_size; + + if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd)) +diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c +index 21e239511..c35ce8915 100644 +--- a/grub-core/disk/diskfilter.c ++++ b/grub-core/disk/diskfilter.c +@@ -188,6 +188,8 @@ scan_disk (const char *name, int accept_diskfilter) + grub_disk_t disk; + static int scan_depth = 0; + ++ grub_dprintf ("diskfilter", "scanning %s\n", name); ++ + if (!accept_diskfilter && is_valid_diskfilter_name (name)) + return 0; + +@@ -1247,6 +1249,7 @@ insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id, + the same. */ + if (pv->disk && grub_disk_native_sectors (disk) >= pv->part_size) + return GRUB_ERR_NONE; ++ grub_dprintf ("diskfilter", "checking %s\n", disk->name); + pv->disk = grub_disk_open (disk->name); + if (!pv->disk) + return grub_errno; +diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c +index 3b5ed5691..af69cc3bc 100644 +--- a/grub-core/disk/efi/efidisk.c ++++ b/grub-core/disk/efi/efidisk.c +@@ -396,6 +396,19 @@ enumerate_disks (void) + free_devices (devices); + } + ++void ++grub_efidisk_reenumerate_disks (void) ++{ ++ free_devices (fd_devices); ++ free_devices (hd_devices); ++ free_devices (cd_devices); ++ fd_devices = 0; ++ hd_devices = 0; ++ cd_devices = 0; ++ ++ enumerate_disks (); ++} ++ + static int + grub_efidisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, + grub_disk_pull_t pull) +@@ -865,6 +878,7 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) + return 0; + } + ++ grub_dprintf ("efidisk", "getting disk for %s\n", device_name); + parent = grub_disk_open (device_name); + grub_free (dup_dp); + +diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c +index c6cba0c8a..57624fde5 100644 +--- a/grub-core/disk/ieee1275/ofdisk.c ++++ b/grub-core/disk/ieee1275/ofdisk.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + static char *last_devpath; + static grub_ieee1275_ihandle_t last_ihandle; +@@ -44,7 +45,7 @@ struct ofdisk_hash_ent + }; + + static grub_err_t +-grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size, ++grub_ofdisk_get_block_size (grub_uint32_t *block_size, + struct ofdisk_hash_ent *op); + + #define OFDISK_HASH_SZ 8 +@@ -225,7 +226,9 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) + char *buf, *bufptr; + unsigned i; + +- if (grub_ieee1275_open (alias->path, &ihandle)) ++ ++ RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle) ++ if (! ihandle) + return; + + /* This method doesn't need memory allocation for the table. Open +@@ -305,7 +308,9 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) + return; + } + +- if (grub_ieee1275_open (alias->path, &ihandle)) ++ RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle); ++ ++ if (! ihandle) + { + grub_free (buf); + grub_free (table); +@@ -461,6 +466,7 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) + grub_ssize_t actual; + grub_uint32_t block_size = 0; + grub_err_t err; ++ struct ofdisk_hash_ent *op; + + if (grub_strncmp (name, "ieee1275/", sizeof ("ieee1275/") - 1) != 0) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, +@@ -471,6 +477,35 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) + + grub_dprintf ("disk", "Opening `%s'.\n", devpath); + ++ op = ofdisk_hash_find (devpath); ++ if (!op) ++ op = ofdisk_hash_add (devpath, NULL); ++ if (!op) ++ { ++ grub_free (devpath); ++ return grub_errno; ++ } ++ ++ /* Check if the call to open is the same to the last disk already opened */ ++ if (last_devpath && !grub_strcmp(op->open_path,last_devpath)) ++ { ++ goto finish; ++ } ++ ++ /* If not, we need to close the previous disk and open the new one */ ++ else { ++ if (last_ihandle){ ++ grub_ieee1275_close (last_ihandle); ++ } ++ last_ihandle = 0; ++ last_devpath = NULL; ++ ++ RETRY_IEEE1275_OFDISK_OPEN(op->open_path, &last_ihandle); ++ if (! last_ihandle) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); ++ last_devpath = op->open_path; ++ } ++ + if (grub_ieee1275_finddevice (devpath, &dev)) + { + grub_free (devpath); +@@ -491,25 +526,18 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a block device"); + } + ++ ++ finish: + /* XXX: There is no property to read the number of blocks. There + should be a property `#blocks', but it is not there. Perhaps it + is possible to use seek for this. */ + disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN; + + { +- struct ofdisk_hash_ent *op; +- op = ofdisk_hash_find (devpath); +- if (!op) +- op = ofdisk_hash_add (devpath, NULL); +- if (!op) +- { +- grub_free (devpath); +- return grub_errno; +- } + disk->id = (unsigned long) op; + disk->data = op->open_path; + +- err = grub_ofdisk_get_block_size (devpath, &block_size, op); ++ err = grub_ofdisk_get_block_size (&block_size, op); + if (err) + { + grub_free (devpath); +@@ -528,13 +556,6 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) + static void + grub_ofdisk_close (grub_disk_t disk) + { +- if (disk->data == last_devpath) +- { +- if (last_ihandle) +- grub_ieee1275_close (last_ihandle); +- last_ihandle = 0; +- last_devpath = NULL; +- } + disk->data = 0; + } + +@@ -551,7 +572,7 @@ grub_ofdisk_prepare (grub_disk_t disk, grub_disk_addr_t sector) + last_ihandle = 0; + last_devpath = NULL; + +- grub_ieee1275_open (disk->data, &last_ihandle); ++ RETRY_IEEE1275_OFDISK_OPEN(disk->data, &last_ihandle); + if (! last_ihandle) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); + last_devpath = disk->data; +@@ -578,12 +599,23 @@ grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, + return err; + grub_ieee1275_read (last_ihandle, buf, size << disk->log_sector_size, + &actual); +- if (actual != (grub_ssize_t) (size << disk->log_sector_size)) ++ int i = 0; ++ while(actual != (grub_ssize_t) (size << disk->log_sector_size)){ ++ if (i>MAX_RETRIES){ + return grub_error (GRUB_ERR_READ_ERROR, N_("failure reading sector 0x%llx " + "from `%s'"), + (unsigned long long) sector, + disk->name); ++ } ++ last_devpath = NULL; ++ err = grub_ofdisk_prepare (disk, sector); ++ if (err) ++ return err; + ++ grub_ieee1275_read (last_ihandle, buf, size << disk->log_sector_size, ++ &actual); ++ i++; ++ } + return 0; + } + +@@ -681,7 +713,7 @@ grub_ofdisk_init (void) + } + + static grub_err_t +-grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size, ++grub_ofdisk_get_block_size (grub_uint32_t *block_size, + struct ofdisk_hash_ent *op) + { + struct size_args_ieee1275 +@@ -694,16 +726,6 @@ grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size, + grub_ieee1275_cell_t size2; + } args_ieee1275; + +- if (last_ihandle) +- grub_ieee1275_close (last_ihandle); +- +- last_ihandle = 0; +- last_devpath = NULL; +- +- grub_ieee1275_open (device, &last_ihandle); +- if (! last_ihandle) +- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); +- + *block_size = 0; + + if (op->block_size_fails >= 2) +diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c +index 4635dcfde..11a5e0cbd 100644 +--- a/grub-core/disk/loopback.c ++++ b/grub-core/disk/loopback.c +@@ -21,20 +21,13 @@ + #include + #include + #include ++#include + #include + #include + #include + + GRUB_MOD_LICENSE ("GPLv3+"); + +-struct grub_loopback +-{ +- char *devname; +- grub_file_t file; +- struct grub_loopback *next; +- unsigned long id; +-}; +- + static struct grub_loopback *loopback_list; + static unsigned long last_id = 0; + +diff --git a/grub-core/disk/mdraid1x_linux.c b/grub-core/disk/mdraid1x_linux.c +index 72e5cb6f4..3b5b6c423 100644 +--- a/grub-core/disk/mdraid1x_linux.c ++++ b/grub-core/disk/mdraid1x_linux.c +@@ -130,6 +130,12 @@ grub_mdraid_detect (grub_disk_t disk, + struct grub_diskfilter_vg *array; + char *uuid; + ++#ifdef __powerpc__ ++ /* Firmware will yell at us for reading too far. */ ++ if (minor_version == 0) ++ continue; ++#endif ++ + if (size == GRUB_DISK_SIZE_UNKNOWN && minor_version == 0) + continue; + +diff --git a/grub-core/disk/mdraid_linux.c b/grub-core/disk/mdraid_linux.c +index e40216f51..98fcfb1be 100644 +--- a/grub-core/disk/mdraid_linux.c ++++ b/grub-core/disk/mdraid_linux.c +@@ -189,6 +189,11 @@ grub_mdraid_detect (grub_disk_t disk, + grub_uint32_t level; + struct grub_diskfilter_vg *ret; + ++#ifdef __powerpc__ ++ /* Firmware will yell at us for reading too far. */ ++ return NULL; ++#endif ++ + /* The sector where the mdraid 0.90 superblock is stored, if available. */ + size = grub_disk_native_sectors (disk); + if (size == GRUB_DISK_SIZE_UNKNOWN) +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index ba0c58352..ad35e7575 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -38,6 +38,10 @@ + #include + #include + #include ++#include ++#include ++#include ++#include + #include + #include + #include +@@ -79,9 +83,11 @@ struct grub_btrfs_superblock + grub_uint64_t generation; + grub_uint64_t root_tree; + grub_uint64_t chunk_tree; +- grub_uint8_t dummy2[0x20]; ++ grub_uint8_t dummy2[0x18]; ++ grub_uint64_t bytes_used; + grub_uint64_t root_dir_objectid; +- grub_uint8_t dummy3[0x41]; ++ grub_uint64_t num_devices; ++ grub_uint8_t dummy3[0x39]; + struct grub_btrfs_device this_device; + char label[0x100]; + grub_uint8_t dummy4[0x100]; +@@ -121,6 +127,7 @@ struct grub_btrfs_data + grub_uint64_t exttree; + grub_size_t extsize; + struct grub_btrfs_extent_data *extent; ++ grub_uint64_t fs_tree; + }; + + struct grub_btrfs_chunk_item +@@ -191,6 +198,14 @@ struct grub_btrfs_leaf_descriptor + } *data; + }; + ++struct grub_btrfs_root_ref ++{ ++ grub_uint64_t dirid; ++ grub_uint64_t sequence; ++ grub_uint16_t name_len; ++ const char name[0]; ++} __attribute__ ((packed)); ++ + struct grub_btrfs_time + { + grub_int64_t sec; +@@ -203,7 +218,7 @@ struct grub_btrfs_inode + grub_uint64_t size; + grub_uint8_t dummy2[0x70]; + struct grub_btrfs_time mtime; +-} GRUB_PACKED; ++} GRUB_PACKED __attribute__ ((aligned(8))); + + struct grub_btrfs_extent_data + { +@@ -236,6 +251,14 @@ struct grub_btrfs_extent_data + + #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100 + ++#define GRUB_BTRFS_ROOT_TREE_OBJECTID 1ULL ++#define GRUB_BTRFS_FS_TREE_OBJECTID 5ULL ++#define GRUB_BTRFS_ROOT_REF_KEY 156 ++#define GRUB_BTRFS_ROOT_ITEM_KEY 132 ++ ++static grub_uint64_t btrfs_default_subvolid = 0; ++static char *btrfs_default_subvol = NULL; ++ + static grub_disk_addr_t superblock_sectors[] = { 64 * 2, 64 * 1024 * 2, + 256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2 + }; +@@ -244,6 +267,12 @@ static grub_err_t + grub_btrfs_read_logical (struct grub_btrfs_data *data, + grub_disk_addr_t addr, void *buf, grub_size_t size, + int recursion_depth); ++static grub_err_t ++get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key, ++ grub_uint64_t *tree, grub_uint8_t *type); ++ ++grub_uint64_t ++find_mtab_subvol_tree (const char *path, char **path_in_subvol); + + static grub_err_t + read_sblock (grub_disk_t disk, struct grub_btrfs_superblock *sb) +@@ -1252,11 +1281,115 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + return GRUB_ERR_NONE; + } + ++static grub_err_t ++get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree, ++ grub_uint64_t objectid, grub_uint64_t offset, ++ grub_uint64_t *fs_root); ++ ++static grub_err_t ++lookup_root_by_id(struct grub_btrfs_data *data, grub_uint64_t id) ++{ ++ grub_err_t err; ++ grub_uint64_t tree; ++ ++ err = get_fs_root(data, data->sblock.root_tree, id, -1, &tree); ++ if (!err) ++ data->fs_tree = tree; ++ return err; ++} ++ ++static grub_err_t ++find_path (struct grub_btrfs_data *data, ++ const char *path, struct grub_btrfs_key *key, ++ grub_uint64_t *tree, grub_uint8_t *type); ++ ++static grub_err_t ++lookup_root_by_name(struct grub_btrfs_data *data, const char *path) ++{ ++ grub_err_t err; ++ grub_uint64_t tree = 0; ++ grub_uint8_t type; ++ grub_uint64_t saved_tree; ++ struct grub_btrfs_key key; ++ ++ if (path[0] == '\0') ++ { ++ data->fs_tree = 0; ++ return GRUB_ERR_NONE; ++ } ++ ++ err = get_root (data, &key, &tree, &type); ++ if (err) ++ return err; ++ ++ saved_tree = data->fs_tree; ++ data->fs_tree = tree; ++ ++ err = find_path (data, path, &key, &tree, &type); ++ ++ data->fs_tree = saved_tree; ++ ++ if (err) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path); ++ ++ if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) ++ return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path); ++ ++ data->fs_tree = tree; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++lookup_root_by_name_fallback(struct grub_btrfs_data *data, const char *path) ++{ ++ grub_err_t err; ++ grub_uint64_t tree = 0; ++ grub_uint8_t type; ++ struct grub_btrfs_key key; ++ ++ err = find_path (data, path, &key, &tree, &type); ++ if (err) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path); ++ ++ if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) ++ return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path); ++ ++ data->fs_tree = tree; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__ ((unused))) ++{ ++ if (btrfs_default_subvol) ++ { ++ grub_err_t err; ++ err = lookup_root_by_name(data, btrfs_default_subvol); ++ ++ /* Fallback to old schemes */ ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ { ++ err = GRUB_ERR_NONE; ++ return lookup_root_by_name_fallback(data, btrfs_default_subvol); ++ } ++ return err; ++ } ++ ++ if (btrfs_default_subvolid) ++ return lookup_root_by_id(data, btrfs_default_subvolid); ++ ++ data->fs_tree = 0; ++ ++ return GRUB_ERR_NONE; ++} ++ ++ + static struct grub_btrfs_data * + grub_btrfs_mount (grub_device_t dev) + { + struct grub_btrfs_data *data; + grub_err_t err; ++ const char *relpath = grub_env_get ("btrfs_relative_path"); + + if (!dev->disk) + { +@@ -1287,6 +1420,16 @@ grub_btrfs_mount (grub_device_t dev) + data->devices_attached[0].dev = dev; + data->devices_attached[0].id = data->sblock.this_device.device_id; + ++ if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) ++ { ++ err = btrfs_handle_subvol (data); ++ if (err) ++ { ++ grub_free (data); ++ return NULL; ++ } ++ } ++ + return data; + } + +@@ -1784,6 +1927,91 @@ get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key, + return GRUB_ERR_NONE; + } + ++static grub_err_t ++find_pathname(struct grub_btrfs_data *data, grub_uint64_t objectid, ++ grub_uint64_t fs_root, const char *name, char **pathname) ++{ ++ grub_err_t err; ++ struct grub_btrfs_key key = { ++ .object_id = objectid, ++ .type = GRUB_BTRFS_ITEM_TYPE_INODE_REF, ++ .offset = 0, ++ }; ++ struct grub_btrfs_key key_out; ++ struct grub_btrfs_leaf_descriptor desc; ++ char *p = grub_strdup (name); ++ grub_disk_addr_t elemaddr; ++ grub_size_t elemsize; ++ grub_size_t alloc = grub_strlen(name) + 1; ++ ++ err = lower_bound(data, &key, &key_out, fs_root, ++ &elemaddr, &elemsize, &desc, 0); ++ if (err) ++ return grub_error(err, "lower_bound caught %d\n", err); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF) ++ next(data, &desc, &elemaddr, &elemsize, &key_out); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF) ++ { ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, ++ "Can't find inode ref for {%"PRIuGRUB_UINT64_T ++ ", %u, %"PRIuGRUB_UINT64_T"} %"PRIuGRUB_UINT64_T ++ "/%"PRIuGRUB_SIZE"\n", ++ key_out.object_id, key_out.type, ++ key_out.offset, elemaddr, elemsize); ++ } ++ ++ ++ while (key_out.type == GRUB_BTRFS_ITEM_TYPE_INODE_REF && ++ key_out.object_id != key_out.offset) { ++ struct grub_btrfs_inode_ref *inode_ref; ++ char *new; ++ ++ inode_ref = grub_malloc(elemsize + 1); ++ if (!inode_ref) ++ return grub_error(GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't allocate memory for inode_ref (%"PRIuGRUB_SIZE")\n", elemsize); ++ ++ err = grub_btrfs_read_logical(data, elemaddr, inode_ref, elemsize, 0); ++ if (err) ++ return grub_error(err, "read_logical caught %d\n", err); ++ ++ alloc += grub_le_to_cpu16 (inode_ref->n) + 2; ++ new = grub_malloc(alloc); ++ if (!new) ++ return grub_error(GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't allocate memory for name (%"PRIuGRUB_SIZE")\n", alloc); ++ ++ grub_memcpy(new, inode_ref->name, grub_le_to_cpu16 (inode_ref->n)); ++ if (p) ++ { ++ new[grub_le_to_cpu16 (inode_ref->n)] = '/'; ++ grub_strcpy (new + grub_le_to_cpu16 (inode_ref->n) + 1, p); ++ grub_free(p); ++ } ++ else ++ new[grub_le_to_cpu16 (inode_ref->n)] = 0; ++ grub_free(inode_ref); ++ ++ p = new; ++ ++ key.object_id = key_out.offset; ++ ++ err = lower_bound(data, &key, &key_out, fs_root, &elemaddr, ++ &elemsize, &desc, 0); ++ if (err) ++ return grub_error(err, "lower_bound caught %d\n", err); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF) ++ next(data, &desc, &elemaddr, &elemsize, &key_out); ++ ++ } ++ ++ *pathname = p; ++ return 0; ++} ++ + static grub_err_t + find_path (struct grub_btrfs_data *data, + const char *path, struct grub_btrfs_key *key, +@@ -1796,31 +2024,66 @@ find_path (struct grub_btrfs_data *data, + grub_size_t allocated = 0; + struct grub_btrfs_dir_item *direl = NULL; + struct grub_btrfs_key key_out; ++ int follow_default; + const char *ctoken; + grub_size_t ctokenlen; + char *path_alloc = NULL; + char *origpath = NULL; + unsigned symlinks_max = 32; ++ const char *relpath = grub_env_get ("btrfs_relative_path"); + +- err = get_root (data, key, tree, type); +- if (err) +- return err; +- ++ follow_default = 0; + origpath = grub_strdup (path); + if (!origpath) + return grub_errno; + ++ if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) ++ { ++ if (data->fs_tree) ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->fs_tree; ++ /* This is a tree root, so everything starts at objectid 256 */ ++ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ } ++ else ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->sblock.root_tree; ++ key->object_id = data->sblock.root_dir_objectid; ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ follow_default = 1; ++ } ++ } ++ else ++ { ++ err = get_root (data, key, tree, type); ++ if (err) ++ return err; ++ } ++ + while (1) + { +- while (path[0] == '/') +- path++; +- if (!path[0]) +- break; +- slash = grub_strchr (path, '/'); +- if (!slash) +- slash = path + grub_strlen (path); +- ctoken = path; +- ctokenlen = slash - path; ++ if (!follow_default) ++ { ++ while (path[0] == '/') ++ path++; ++ if (!path[0]) ++ break; ++ slash = grub_strchr (path, '/'); ++ if (!slash) ++ slash = path + grub_strlen (path); ++ ctoken = path; ++ ctokenlen = slash - path; ++ } ++ else ++ { ++ ctoken = "default"; ++ ctokenlen = sizeof ("default") - 1; ++ } + + if (*type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) + { +@@ -1831,7 +2094,9 @@ find_path (struct grub_btrfs_data *data, + + if (ctokenlen == 1 && ctoken[0] == '.') + { +- path = slash; ++ if (!follow_default) ++ path = slash; ++ follow_default = 0; + continue; + } + if (ctokenlen == 2 && ctoken[0] == '.' && ctoken[1] == '.') +@@ -1862,8 +2127,9 @@ find_path (struct grub_btrfs_data *data, + *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; + key->object_id = key_out.offset; + +- path = slash; +- ++ if (!follow_default) ++ path = slash; ++ follow_default = 0; + continue; + } + +@@ -1932,7 +2198,9 @@ find_path (struct grub_btrfs_data *data, + return err; + } + +- path = slash; ++ if (!follow_default) ++ path = slash; ++ follow_default = 0; + if (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK) + { + struct grub_btrfs_inode inode; +@@ -1982,13 +2250,37 @@ find_path (struct grub_btrfs_data *data, + path = path_alloc = tmp; + if (path[0] == '/') + { +- err = get_root (data, key, tree, type); +- if (err) ++ if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) + { +- grub_free (direl); +- grub_free (path_alloc); +- grub_free (origpath); +- return err; ++ if (data->fs_tree) ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->fs_tree; ++ /* This is a tree root, so everything starts at objectid 256 */ ++ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ } ++ else ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->sblock.root_tree; ++ key->object_id = data->sblock.root_dir_objectid; ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ follow_default = 1; ++ } ++ } ++ else ++ { ++ err = get_root (data, key, tree, type); ++ if (err) ++ { ++ grub_free (direl); ++ grub_free (path_alloc); ++ grub_free (origpath); ++ return err; ++ } + } + } + continue; +@@ -2078,11 +2370,20 @@ grub_btrfs_dir (grub_device_t device, const char *path, + grub_uint64_t tree; + grub_uint8_t type; + grub_size_t est_size = 0; ++ char *new_path = NULL; + + if (!data) + return grub_errno; + +- err = find_path (data, path, &key_in, &tree, &type); ++ tree = find_mtab_subvol_tree (path, &new_path); ++ ++ if (tree) ++ data->fs_tree = tree; ++ ++ err = find_path (data, new_path ? new_path : path, &key_in, &tree, &type); ++ if (new_path) ++ grub_free (new_path); ++ + if (err) + { + grub_btrfs_unmount (data); +@@ -2209,11 +2510,21 @@ grub_btrfs_open (struct grub_file *file, const char *name) + struct grub_btrfs_inode inode; + grub_uint8_t type; + struct grub_btrfs_key key_in; ++ grub_uint64_t tree; ++ char *new_path = NULL; + + if (!data) + return grub_errno; + +- err = find_path (data, name, &key_in, &data->tree, &type); ++ tree = find_mtab_subvol_tree (name, &new_path); ++ ++ if (tree) ++ data->fs_tree = tree; ++ ++ err = find_path (data, new_path ? new_path : name, &key_in, &data->tree, &type); ++ if (new_path) ++ grub_free (new_path); ++ + if (err) + { + grub_btrfs_unmount (data); +@@ -2256,6 +2567,20 @@ grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len) + data->tree, file->offset, buf, len); + } + ++static char * ++btrfs_unparse_uuid(struct grub_btrfs_data *data) ++{ ++ return grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", ++ grub_be_to_cpu16 (data->sblock.uuid[0]), ++ grub_be_to_cpu16 (data->sblock.uuid[1]), ++ grub_be_to_cpu16 (data->sblock.uuid[2]), ++ grub_be_to_cpu16 (data->sblock.uuid[3]), ++ grub_be_to_cpu16 (data->sblock.uuid[4]), ++ grub_be_to_cpu16 (data->sblock.uuid[5]), ++ grub_be_to_cpu16 (data->sblock.uuid[6]), ++ grub_be_to_cpu16 (data->sblock.uuid[7])); ++} ++ + static grub_err_t + grub_btrfs_uuid (grub_device_t device, char **uuid) + { +@@ -2267,15 +2592,7 @@ grub_btrfs_uuid (grub_device_t device, char **uuid) + if (!data) + return grub_errno; + +- *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", +- grub_be_to_cpu16 (data->sblock.uuid[0]), +- grub_be_to_cpu16 (data->sblock.uuid[1]), +- grub_be_to_cpu16 (data->sblock.uuid[2]), +- grub_be_to_cpu16 (data->sblock.uuid[3]), +- grub_be_to_cpu16 (data->sblock.uuid[4]), +- grub_be_to_cpu16 (data->sblock.uuid[5]), +- grub_be_to_cpu16 (data->sblock.uuid[6]), +- grub_be_to_cpu16 (data->sblock.uuid[7])); ++ *uuid = btrfs_unparse_uuid(data); + + grub_btrfs_unmount (data); + +@@ -2396,6 +2713,618 @@ grub_btrfs_embed (grub_device_t device __attribute__ ((unused)), + } + #endif + ++static grub_err_t ++grub_cmd_btrfs_info (grub_command_t cmd __attribute__ ((unused)), int argc, ++ char **argv) ++{ ++ grub_device_t dev; ++ char *devname; ++ struct grub_btrfs_data *data; ++ char *uuid; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ ++ if (!devname) ++ return grub_errno; ++ ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ if (!dev) ++ return grub_errno; ++ ++ data = grub_btrfs_mount (dev); ++ if (!data) ++ { ++ grub_device_close(dev); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "failed to open fs"); ++ } ++ ++ if (data->sblock.label[0]) ++ grub_printf("Label: '%s' ", data->sblock.label); ++ else ++ grub_printf("Label: none "); ++ ++ uuid = btrfs_unparse_uuid(data); ++ ++ grub_printf(" uuid: %s\n\tTotal devices %" PRIuGRUB_UINT64_T ++ " FS bytes used %" PRIuGRUB_UINT64_T "\n", ++ uuid, grub_cpu_to_le64(data->sblock.num_devices), ++ grub_cpu_to_le64(data->sblock.bytes_used)); ++ ++ grub_btrfs_unmount (data); ++ ++ return 0; ++} ++ ++struct grub_btrfs_mtab ++{ ++ struct grub_btrfs_mtab *next; ++ struct grub_btrfs_mtab **prev; ++ char *path; ++ char *subvol; ++ grub_uint64_t tree; ++}; ++ ++typedef struct grub_btrfs_mtab* grub_btrfs_mtab_t; ++ ++static struct grub_btrfs_mtab *btrfs_mtab; ++ ++#define FOR_GRUB_MTAB(var) FOR_LIST_ELEMENTS (var, btrfs_mtab) ++#define FOR_GRUB_MTAB_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE((var), (next), btrfs_mtab) ++ ++static void ++add_mountpoint (const char *path, const char *subvol, grub_uint64_t tree) ++{ ++ grub_btrfs_mtab_t m = grub_malloc (sizeof (*m)); ++ ++ m->path = grub_strdup (path); ++ m->subvol = grub_strdup (subvol); ++ m->tree = tree; ++ grub_list_push (GRUB_AS_LIST_P (&btrfs_mtab), GRUB_AS_LIST (m)); ++} ++ ++static grub_err_t ++grub_cmd_btrfs_mount_subvol (grub_command_t cmd __attribute__ ((unused)), int argc, ++ char **argv) ++{ ++ char *devname, *dirname, *subvol; ++ struct grub_btrfs_key key_in; ++ grub_uint8_t type; ++ grub_uint64_t tree; ++ grub_uint64_t saved_tree; ++ grub_err_t err; ++ struct grub_btrfs_data *data = NULL; ++ grub_device_t dev = NULL; ++ ++ if (argc < 3) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "required and "); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ ++ if (!dev) ++ { ++ err = grub_errno; ++ goto err_out; ++ } ++ ++ dirname = argv[1]; ++ subvol = argv[2]; ++ ++ data = grub_btrfs_mount (dev); ++ if (!data) ++ { ++ err = grub_errno; ++ goto err_out; ++ } ++ ++ err = find_path (data, dirname, &key_in, &tree, &type); ++ if (err) ++ goto err_out; ++ ++ if (type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); ++ goto err_out; ++ } ++ ++ err = get_root (data, &key_in, &tree, &type); ++ ++ if (err) ++ goto err_out; ++ ++ saved_tree = data->fs_tree; ++ data->fs_tree = tree; ++ err = find_path (data, subvol, &key_in, &tree, &type); ++ data->fs_tree = saved_tree; ++ ++ if (err) ++ goto err_out; ++ ++ if (key_in.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", subvol); ++ goto err_out; ++ } ++ ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ add_mountpoint (dirname, subvol, tree); ++ ++ return GRUB_ERR_NONE; ++ ++err_out: ++ ++ if (data) ++ grub_btrfs_unmount (data); ++ ++ if (dev) ++ grub_device_close (dev); ++ ++ return err; ++} ++ ++grub_uint64_t ++find_mtab_subvol_tree (const char *path, char **path_in_subvol) ++{ ++ grub_btrfs_mtab_t m, cm; ++ grub_uint64_t tree; ++ ++ if (!path || !path_in_subvol) ++ return 0; ++ ++ *path_in_subvol = NULL; ++ tree = 0; ++ cm = NULL; ++ ++ FOR_GRUB_MTAB (m) ++ { ++ if (grub_strncmp (path, m->path, grub_strlen (m->path)) == 0) ++ { ++ if (!cm) ++ cm = m; ++ else ++ if (grub_strcmp (m->path, cm->path) > 0) ++ cm = m; ++ } ++ } ++ ++ if (cm) ++ { ++ const char *s = path + grub_strlen (cm->path); ++ *path_in_subvol = (s[0] == '\0') ? grub_strdup ("/") : grub_strdup (s); ++ tree = cm->tree; ++ } ++ ++ return tree; ++} ++ ++static grub_err_t ++get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree, ++ grub_uint64_t objectid, grub_uint64_t offset, ++ grub_uint64_t *fs_root) ++{ ++ grub_err_t err; ++ struct grub_btrfs_key key_in = { ++ .object_id = objectid, ++ .type = GRUB_BTRFS_ROOT_ITEM_KEY, ++ .offset = offset, ++ }, key_out; ++ struct grub_btrfs_leaf_descriptor desc; ++ grub_disk_addr_t elemaddr; ++ grub_size_t elemsize; ++ struct grub_btrfs_root_item ri; ++ ++ err = lower_bound(data, &key_in, &key_out, tree, ++ &elemaddr, &elemsize, &desc, 0); ++ ++ if (err) ++ return err; ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM || elemaddr == 0) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, ++ N_("can't find fs root for subvol %"PRIuGRUB_UINT64_T"\n"), ++ key_in.object_id); ++ ++ err = grub_btrfs_read_logical (data, elemaddr, &ri, sizeof (ri), 0); ++ if (err) ++ return err; ++ ++ *fs_root = ri.tree; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static const struct grub_arg_option options[] = { ++ {"output", 'o', 0, N_("Output to a variable instead of the console."), ++ N_("VARNAME"), ARG_TYPE_STRING}, ++ {"path-only", 'p', 0, N_("Show only the path of the subvolume."), 0, 0}, ++ {"id-only", 'i', 0, N_("Show only the id of the subvolume."), 0, 0}, ++ {0, 0, 0, 0, 0, 0} ++}; ++ ++static grub_err_t ++grub_cmd_btrfs_list_subvols (struct grub_extcmd_context *ctxt, ++ int argc, char **argv) ++{ ++ struct grub_btrfs_data *data; ++ grub_device_t dev; ++ char *devname; ++ grub_uint64_t tree; ++ struct grub_btrfs_key key_in = { ++ .object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID), ++ .type = GRUB_BTRFS_ROOT_REF_KEY, ++ .offset = 0, ++ }, key_out; ++ struct grub_btrfs_leaf_descriptor desc; ++ grub_disk_addr_t elemaddr; ++ grub_uint64_t fs_root = 0; ++ grub_size_t elemsize; ++ grub_size_t allocated = 0; ++ int r = 0; ++ grub_err_t err; ++ char *buf = NULL; ++ int print = 1; ++ int path_only = ctxt->state[1].set; ++ int num_only = ctxt->state[2].set; ++ char *varname = NULL; ++ char *output = NULL; ++ ++ if (ctxt->state[0].set) { ++ varname = ctxt->state[0].arg; ++ print = 0; ++ } ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ if (!devname) ++ return grub_errno; ++ ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ if (!dev) ++ return grub_errno; ++ ++ data = grub_btrfs_mount(dev); ++ if (!data) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "could not open device"); ++ ++ tree = data->sblock.root_tree; ++ err = get_fs_root(data, tree, grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID), ++ 0, &fs_root); ++ if (err) ++ goto out; ++ ++ err = lower_bound(data, &key_in, &key_out, tree, ++ &elemaddr, &elemsize, &desc, 0); ++ ++ if (err) ++ { ++ grub_btrfs_unmount(data); ++ return err; ++ } ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF || elemaddr == 0) ++ { ++ r = next(data, &desc, &elemaddr, &elemsize, &key_out); ++ } ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF) { ++ err = GRUB_ERR_FILE_NOT_FOUND; ++ grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root refs")); ++ goto out; ++ } ++ ++ do ++ { ++ struct grub_btrfs_root_ref *ref; ++ char *p = NULL; ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF) ++ { ++ r = 0; ++ break; ++ } ++ ++ if (elemsize > allocated) ++ { ++ grub_free(buf); ++ allocated = 2 * elemsize; ++ buf = grub_malloc(allocated + 1); ++ if (!buf) ++ { ++ r = -grub_errno; ++ break; ++ } ++ } ++ ref = (struct grub_btrfs_root_ref *)buf; ++ ++ err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0); ++ if (err) ++ { ++ r = -err; ++ break; ++ } ++ buf[elemsize] = 0; ++ ++ find_pathname(data, ref->dirid, fs_root, ref->name, &p); ++ ++ if (print) ++ { ++ if (num_only) ++ grub_printf("ID %"PRIuGRUB_UINT64_T"\n", key_out.offset); ++ else if (path_only) ++ grub_printf("%s\n", p); ++ else ++ grub_printf("ID %"PRIuGRUB_UINT64_T" path %s\n", key_out.offset, p); ++ } else { ++ char *old = output; ++ if (num_only) ++ output = grub_xasprintf("%s%"PRIuGRUB_UINT64_T"\n", ++ old ?: "", key_out.offset); ++ else if (path_only) ++ output = grub_xasprintf("%s%s\n", old ?: "", p); ++ else ++ output = grub_xasprintf("%sID %"PRIuGRUB_UINT64_T" path %s\n", ++ old ?: "", key_out.offset, p); ++ ++ if (old) ++ grub_free(old); ++ } ++ ++ r = next(data, &desc, &elemaddr, &elemsize, &key_out); ++ } while(r > 0); ++ ++ if (output) ++ grub_env_set(varname, output); ++ ++out: ++ free_iterator(&desc); ++ grub_btrfs_unmount(data); ++ ++ grub_device_close (dev); ++ ++ return 0; ++} ++ ++static grub_err_t ++grub_btrfs_get_parent_subvol_path (struct grub_btrfs_data *data, ++ grub_uint64_t child_id, ++ const char *child_path, ++ grub_uint64_t *parent_id, ++ char **path_out) ++{ ++ grub_uint64_t fs_root = 0; ++ struct grub_btrfs_key key_in = { ++ .object_id = child_id, ++ .type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF, ++ .offset = 0, ++ }, key_out; ++ struct grub_btrfs_root_ref *ref; ++ char *buf; ++ struct grub_btrfs_leaf_descriptor desc; ++ grub_size_t elemsize; ++ grub_disk_addr_t elemaddr; ++ grub_err_t err; ++ char *parent_path; ++ ++ *parent_id = 0; ++ *path_out = 0; ++ ++ err = lower_bound(data, &key_in, &key_out, data->sblock.root_tree, ++ &elemaddr, &elemsize, &desc, 0); ++ if (err) ++ return err; ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF || elemaddr == 0) ++ next(data, &desc, &elemaddr, &elemsize, &key_out); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF) ++ { ++ free_iterator(&desc); ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root backrefs")); ++ } ++ ++ buf = grub_malloc(elemsize + 1); ++ if (!buf) ++ { ++ free_iterator(&desc); ++ return grub_errno; ++ } ++ ++ err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0); ++ if (err) ++ { ++ grub_free(buf); ++ free_iterator(&desc); ++ return err; ++ } ++ ++ buf[elemsize] = 0; ++ ref = (struct grub_btrfs_root_ref *)buf; ++ ++ err = get_fs_root(data, data->sblock.root_tree, grub_le_to_cpu64 (key_out.offset), ++ 0, &fs_root); ++ if (err) ++ { ++ grub_free(buf); ++ free_iterator(&desc); ++ return err; ++ } ++ ++ find_pathname(data, grub_le_to_cpu64 (ref->dirid), fs_root, ref->name, &parent_path); ++ ++ if (child_path) ++ { ++ *path_out = grub_xasprintf ("%s/%s", parent_path, child_path); ++ grub_free (parent_path); ++ } ++ else ++ *path_out = parent_path; ++ ++ *parent_id = grub_le_to_cpu64 (key_out.offset); ++ ++ grub_free(buf); ++ free_iterator(&desc); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_btrfs_get_default_subvolume_id (struct grub_btrfs_data *data, grub_uint64_t *id) ++{ ++ grub_err_t err; ++ grub_disk_addr_t elemaddr; ++ grub_size_t elemsize; ++ struct grub_btrfs_key key, key_out; ++ struct grub_btrfs_dir_item *direl = NULL; ++ const char *ctoken = "default"; ++ grub_size_t ctokenlen = sizeof ("default") - 1; ++ ++ *id = 0; ++ key.object_id = data->sblock.root_dir_objectid; ++ key.type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key.offset = grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken, ctokenlen)); ++ err = lower_bound (data, &key, &key_out, data->sblock.root_tree, &elemaddr, &elemsize, ++ NULL, 0); ++ if (err) ++ return err; ++ ++ if (key_cmp (&key, &key_out) != 0) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found")); ++ ++ struct grub_btrfs_dir_item *cdirel; ++ direl = grub_malloc (elemsize + 1); ++ err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize, 0); ++ if (err) ++ { ++ grub_free (direl); ++ return err; ++ } ++ for (cdirel = direl; ++ (grub_uint8_t *) cdirel - (grub_uint8_t *) direl ++ < (grub_ssize_t) elemsize; ++ cdirel = (void *) ((grub_uint8_t *) (direl + 1) ++ + grub_le_to_cpu16 (cdirel->n) ++ + grub_le_to_cpu16 (cdirel->m))) ++ { ++ if (ctokenlen == grub_le_to_cpu16 (cdirel->n) ++ && grub_memcmp (cdirel->name, ctoken, ctokenlen) == 0) ++ break; ++ } ++ if ((grub_uint8_t *) cdirel - (grub_uint8_t *) direl ++ >= (grub_ssize_t) elemsize) ++ { ++ grub_free (direl); ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found")); ++ return err; ++ } ++ ++ if (cdirel->key.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM) ++ { ++ grub_free (direl); ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found")); ++ return err; ++ } ++ ++ *id = grub_le_to_cpu64 (cdirel->key.object_id); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_btrfs_get_default_subvol (struct grub_extcmd_context *ctxt, ++ int argc, char **argv) ++{ ++ char *devname; ++ grub_device_t dev; ++ struct grub_btrfs_data *data; ++ grub_err_t err; ++ grub_uint64_t id; ++ char *subvol = NULL; ++ grub_uint64_t subvolid = 0; ++ char *varname = NULL; ++ char *output = NULL; ++ int path_only = ctxt->state[1].set; ++ int num_only = ctxt->state[2].set; ++ ++ if (ctxt->state[0].set) ++ varname = ctxt->state[0].arg; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ if (!devname) ++ return grub_errno; ++ ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ if (!dev) ++ return grub_errno; ++ ++ data = grub_btrfs_mount(dev); ++ if (!data) ++ { ++ grub_device_close (dev); ++ grub_dprintf ("btrfs", "failed to open fs\n"); ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ ++ err = grub_btrfs_get_default_subvolume_id (data, &subvolid); ++ if (err) ++ { ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ return err; ++ } ++ ++ id = subvolid; ++ while (id != GRUB_BTRFS_ROOT_VOL_OBJECTID) ++ { ++ grub_uint64_t parent_id; ++ char *path_out; ++ ++ err = grub_btrfs_get_parent_subvol_path (data, grub_cpu_to_le64 (id), subvol, &parent_id, &path_out); ++ if (err) ++ { ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ return err; ++ } ++ ++ if (subvol) ++ grub_free (subvol); ++ subvol = path_out; ++ id = parent_id; ++ } ++ ++ if (num_only && path_only) ++ output = grub_xasprintf ("%"PRIuGRUB_UINT64_T" /%s", subvolid, subvol); ++ else if (num_only) ++ output = grub_xasprintf ("%"PRIuGRUB_UINT64_T, subvolid); ++ else ++ output = grub_xasprintf ("/%s", subvol); ++ ++ if (varname) ++ grub_env_set(varname, output); ++ else ++ grub_printf ("%s\n", output); ++ ++ grub_free (output); ++ grub_free (subvol); ++ ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ ++ return GRUB_ERR_NONE; ++} ++ + static struct grub_fs grub_btrfs_fs = { + .name = "btrfs", + .fs_dir = grub_btrfs_dir, +@@ -2411,12 +3340,101 @@ static struct grub_fs grub_btrfs_fs = { + #endif + }; + ++static grub_command_t cmd_info; ++static grub_command_t cmd_mount_subvol; ++static grub_extcmd_t cmd_list_subvols; ++static grub_extcmd_t cmd_get_default_subvol; ++ ++static char * ++subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ unsigned long long result = 0; ++ ++ grub_errno = GRUB_ERR_NONE; ++ if (*val) ++ { ++ result = grub_strtoull(val, NULL, 10); ++ if (grub_errno) ++ return NULL; ++ } ++ ++ grub_free (btrfs_default_subvol); ++ btrfs_default_subvol = NULL; ++ btrfs_default_subvolid = result; ++ return grub_strdup(val); ++} ++ ++static const char * ++subvolid_get_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ if (btrfs_default_subvol) ++ return grub_xasprintf("subvol:%s", btrfs_default_subvol); ++ else if (btrfs_default_subvolid) ++ return grub_xasprintf("%"PRIuGRUB_UINT64_T, btrfs_default_subvolid); ++ else ++ return ""; ++} ++ ++static char * ++subvol_set_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ grub_free (btrfs_default_subvol); ++ btrfs_default_subvol = grub_strdup (val); ++ btrfs_default_subvolid = 0; ++ return grub_strdup(val); ++} ++ ++static const char * ++subvol_get_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ if (btrfs_default_subvol) ++ return btrfs_default_subvol; ++ else if (btrfs_default_subvolid) ++ return grub_xasprintf("subvolid:%" PRIuGRUB_UINT64_T, ++ btrfs_default_subvolid); ++ else ++ return ""; ++} ++ + GRUB_MOD_INIT (btrfs) + { + grub_fs_register (&grub_btrfs_fs); ++ cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info, ++ "DEVICE", ++ "Print BtrFS info about DEVICE."); ++ cmd_mount_subvol = grub_register_command("btrfs-mount-subvol", grub_cmd_btrfs_mount_subvol, ++ "DEVICE DIRECTORY SUBVOL", ++ "Set btrfs DEVICE the DIRECTORY a mountpoint of SUBVOL."); ++ cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols", ++ grub_cmd_btrfs_list_subvols, 0, ++ "[-p|-n] [-o var] DEVICE", ++ "Print list of BtrFS subvolumes on " ++ "DEVICE.", options); ++ cmd_get_default_subvol = grub_register_extcmd("btrfs-get-default-subvol", ++ grub_cmd_btrfs_get_default_subvol, 0, ++ "[-p|-n] [-o var] DEVICE", ++ "Print default BtrFS subvolume on " ++ "DEVICE.", options); ++ grub_register_variable_hook ("btrfs_subvol", subvol_get_env, ++ subvol_set_env); ++ grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env, ++ subvolid_set_env); ++ grub_env_export ("btrfs_subvol"); ++ grub_env_export ("btrfs_subvolid"); ++ grub_env_export ("btrfs_relative_path"); + } + + GRUB_MOD_FINI (btrfs) + { ++ grub_register_variable_hook ("btrfs_subvol", NULL, NULL); ++ grub_register_variable_hook ("btrfs_subvolid", NULL, NULL); ++ grub_unregister_command (cmd_info); ++ grub_unregister_extcmd (cmd_list_subvols); + grub_fs_unregister (&grub_btrfs_fs); + } ++ ++// vim: si et sw=2: +diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c +index 36b26ac98..42818c376 100644 +--- a/grub-core/fs/reiserfs.c ++++ b/grub-core/fs/reiserfs.c +@@ -42,16 +42,6 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + +-#define MIN(a, b) \ +- ({ typeof (a) _a = (a); \ +- typeof (b) _b = (b); \ +- _a < _b ? _a : _b; }) +- +-#define MAX(a, b) \ +- ({ typeof (a) _a = (a); \ +- typeof (b) _b = (b); \ +- _a > _b ? _a : _b; }) +- + #define REISERFS_SUPER_BLOCK_OFFSET 0x10000 + #define REISERFS_MAGIC_LEN 12 + #define REISERFS_MAGIC_STRING "ReIsEr" +@@ -1076,7 +1066,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + grub_reiserfs_set_key_type (&key, GRUB_REISERFS_ANY, 2); + initial_position = off; + current_position = 0; +- final_position = MIN (len + initial_position, node->size); ++ final_position = grub_min (len + initial_position, node->size); + grub_dprintf ("reiserfs", + "Reading from %lld to %lld (%lld instead of requested %ld)\n", + (unsigned long long) initial_position, +@@ -1115,8 +1105,8 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block); + if (initial_position < current_position + item_size) + { +- offset = MAX ((signed) (initial_position - current_position), 0); +- length = (MIN (item_size, final_position - current_position) ++ offset = grub_max ((signed) (initial_position - current_position), 0); ++ length = (grub_min (item_size, final_position - current_position) + - offset); + grub_dprintf ("reiserfs", + "Reading direct block %u from %u to %u...\n", +@@ -1161,9 +1151,9 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block); + if (current_position + block_size >= initial_position) + { +- offset = MAX ((signed) (initial_position - current_position), +- 0); +- length = (MIN (block_size, final_position - current_position) ++ offset = grub_max ((signed) (initial_position - current_position), ++ 0); ++ length = (grub_min (block_size, final_position - current_position) + - offset); + grub_dprintf ("reiserfs", + "Reading indirect block %u from %u to %u...\n", +@@ -1205,7 +1195,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + switch (found.type) + { + case GRUB_REISERFS_DIRECT: +- read_length = MIN (len, item_size - file->offset); ++ read_length = grub_min (len, item_size - file->offset); + grub_disk_read (found.data->disk, + (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE, + grub_le_to_cpu16 (found.header.item_location) + file->offset, +@@ -1224,12 +1214,12 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + item_size, (char *) indirect_block_ptr); + if (grub_errno) + goto fail; +- len = MIN (len, file->size - file->offset); ++ len = grub_min (len, file->size - file->offset); + for (indirect_block = file->offset / block_size; + indirect_block < indirect_block_count && read_length < len; + indirect_block++) + { +- read = MIN (block_size, len - read_length); ++ read = grub_min (block_size, len - read_length); + grub_disk_read (found.data->disk, + (grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) * block_size) / GRUB_DISK_SECTOR_SIZE, + file->offset % block_size, read, +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index bc2224dbb..8e02ab4a3 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -902,6 +902,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + grub_xfs_first_de(dir->data, dirblock); + int entries = -1; + char *end = dirblock + dirblk_size; ++ grub_uint32_t magic; + + numread = grub_xfs_read_file (dir, 0, 0, + blk << dirblk_log2, +@@ -912,6 +913,15 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + return 0; + } + ++ /* ++ * If this data block isn't actually part of the extent list then ++ * grub_xfs_read_file() returns a block of zeros. So, if the magic ++ * number field is all zeros then this block should be skipped. ++ */ ++ magic = *(grub_uint32_t *)(void *) dirblock; ++ if (!magic) ++ continue; ++ + /* + * Leaf and tail information are only in the data block if the number + * of extents is 1. +diff --git a/grub-core/gdb/cstub.c b/grub-core/gdb/cstub.c +index b64acd70f..99281472d 100644 +--- a/grub-core/gdb/cstub.c ++++ b/grub-core/gdb/cstub.c +@@ -215,7 +215,6 @@ grub_gdb_trap (int trap_no) + grub_printf ("Unhandled exception 0x%x at ", trap_no); + grub_backtrace_print_address ((void *) grub_gdb_regs[PC]); + grub_printf ("\n"); +- grub_backtrace_pointer ((void *) grub_gdb_regs[EBP]); + grub_fatal ("Unhandled exception"); + } + +diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in +index e57c4d920..337753c57 100644 +--- a/grub-core/genmod.sh.in ++++ b/grub-core/genmod.sh.in +@@ -57,8 +57,11 @@ if test x@TARGET_APPLE_LINKER@ != x1; then + @TARGET_STRIP@ --strip-unneeded \ + -K grub_mod_init -K grub_mod_fini \ + -K _grub_mod_init -K _grub_mod_fini \ +- -R .note.gnu.gold-version -R .note.GNU-stack \ ++ -R .note.GNU-stack \ ++ -R .note.gnu.gold-version \ ++ -R .note.gnu.property \ + -R .gnu.build.attributes \ ++ -R '.llvm*' \ + -R .rel.gnu.build.attributes \ + -R .rela.gnu.build.attributes \ + -R .eh_frame -R .rela.eh_frame -R .rel.eh_frame \ +diff --git a/grub-core/genmoddep.awk b/grub-core/genmoddep.awk +index cc987a53a..ab457cb2b 100644 +--- a/grub-core/genmoddep.awk ++++ b/grub-core/genmoddep.awk +@@ -35,7 +35,7 @@ BEGIN { + for (i = 3; i <= NF; i++) { + modtab[$2] = modtab[$2] " " $i; + } +- } ++ } else if ($1 == "") {} #Skip empty lines + else { + printf "error: %u: unrecognized input format\n", NR >"/dev/stderr"; + error++; +diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c +index 7a1c14e4f..631af7a94 100644 +--- a/grub-core/gettext/gettext.c ++++ b/grub-core/gettext/gettext.c +@@ -424,6 +424,13 @@ grub_gettext_init_ext (struct grub_gettext_context *ctx, + grub_free (lang); + } + ++ /* If no translations are available, fall back to untranslated text. */ ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ + if (locale[0] == 'e' && locale[1] == 'n' + && (locale[2] == '\0' || locale[2] == '_')) + grub_errno = err = GRUB_ERR_NONE; +diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c +index a458c3aca..163773153 100644 +--- a/grub-core/io/bufio.c ++++ b/grub-core/io/bufio.c +@@ -139,7 +139,7 @@ grub_bufio_read (grub_file_t file, char *buf, grub_size_t len) + return res; + + /* Need to read some more. */ +- next_buf = (file->offset + res + len - 1) & ~((grub_off_t) bufio->block_size - 1); ++ next_buf = (grub_divmod64 (file->offset + res + len - 1, bufio->block_size, NULL)) * bufio->block_size; + /* Now read between file->offset + res and bufio->buffer_at. */ + if (file->offset + res < next_buf) + { +diff --git a/grub-core/kern/acpi.c b/grub-core/kern/acpi.c +index 48ded4e2e..8ff0835d5 100644 +--- a/grub-core/kern/acpi.c ++++ b/grub-core/kern/acpi.c +@@ -75,7 +75,7 @@ grub_acpi_xsdt_find_table (struct grub_acpi_table_header *xsdt, const char *sig) + return 0; + + ptr = (grub_unaligned_uint64_t *) (xsdt + 1); +- s = (xsdt->length - sizeof (*xsdt)) / sizeof (grub_uint32_t); ++ s = (xsdt->length - sizeof (*xsdt)) / sizeof (grub_uint64_t); + for (; s; s--, ptr++) + { + struct grub_acpi_table_header *tbl; +diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c +index eab9d17ff..926073793 100644 +--- a/grub-core/kern/arm/dl.c ++++ b/grub-core/kern/arm/dl.c +@@ -278,3 +278,16 @@ grub_arch_dl_check_header (void *ehdr) + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/arm/efi/startup.S b/grub-core/kern/arm/efi/startup.S +index 9f8265315..f3bc41f9d 100644 +--- a/grub-core/kern/arm/efi/startup.S ++++ b/grub-core/kern/arm/efi/startup.S +@@ -23,6 +23,8 @@ + .file "startup.S" + .text + .arm ++ .globl start, _start ++FUNCTION(start) + FUNCTION(_start) + /* + * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in r1/r0. +diff --git a/grub-core/kern/arm/startup.S b/grub-core/kern/arm/startup.S +index 3946fe8e1..5679a1d00 100644 +--- a/grub-core/kern/arm/startup.S ++++ b/grub-core/kern/arm/startup.S +@@ -48,6 +48,8 @@ + + .text + .arm ++ .globl start, _start ++FUNCTION(start) + FUNCTION(_start) + b codestart + +diff --git a/grub-core/kern/arm64/backtrace.c b/grub-core/kern/arm64/backtrace.c +new file mode 100644 +index 000000000..019c6fdfe +--- /dev/null ++++ b/grub-core/kern/arm64/backtrace.c +@@ -0,0 +1,94 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_STACK_FRAME 102400 ++ ++struct fplr ++{ ++ void *lr; ++ struct fplr *fp; ++}; ++ ++void ++grub_backtrace_pointer (void *frame, unsigned int skip) ++{ ++ unsigned int x = 0; ++ struct fplr *fplr = (struct fplr *)frame; ++ ++ while (fplr) ++ { ++ const char *name = NULL; ++ char *addr = NULL; ++ ++ grub_dprintf("backtrace", "fp is %p next_fp is %p\n", ++ fplr, fplr->fp); ++ ++ if (x >= skip) ++ { ++ name = grub_get_symbol_by_addr (fplr->lr, 1); ++ if (name) ++ addr = grub_resolve_symbol (name); ++ grub_backtrace_print_address (fplr->lr); ++ ++ if (addr && addr != fplr->lr) ++ grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr, ++ (void *)((grub_uint64_t)fplr->lr - (grub_uint64_t)addr)); ++ else ++ grub_printf(" %s() %p \n", name ? name : "unknown", addr); ++ ++ } ++ ++ x += 1; ++ ++ if (fplr->fp < fplr || ++ (grub_uint64_t)fplr->fp - (grub_uint64_t)fplr > MAX_STACK_FRAME || ++ fplr->fp == fplr) ++ { ++ break; ++ } ++ fplr = fplr->fp; ++ } ++} ++ ++asm ("\t.global \"_text\"\n" ++ "_text:\n" ++ "\t.quad .text\n" ++ "\t.global \"_data\"\n" ++ "_data:\n" ++ "\t.quad .data\n" ++ ); ++ ++extern grub_uint64_t _text; ++extern grub_uint64_t _data; ++ ++void ++grub_backtrace_arch (unsigned int skip) ++{ ++ grub_printf ("Backtrace (.text %p .data %p):\n", ++ (void *)_text, (void *)_data); ++ skip += 1; ++ grub_backtrace_pointer(__builtin_frame_address(0), skip); ++} +diff --git a/grub-core/kern/arm64/dl.c b/grub-core/kern/arm64/dl.c +index a2b5789a9..95c6d5bf4 100644 +--- a/grub-core/kern/arm64/dl.c ++++ b/grub-core/kern/arm64/dl.c +@@ -196,3 +196,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/arm64/efi/startup.S b/grub-core/kern/arm64/efi/startup.S +index 666a7ee3c..41676bdb2 100644 +--- a/grub-core/kern/arm64/efi/startup.S ++++ b/grub-core/kern/arm64/efi/startup.S +@@ -19,7 +19,9 @@ + #include + + .file "startup.S" ++ .globl start, _start + .text ++FUNCTION(start) + FUNCTION(_start) + /* + * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in x1/x0. +diff --git a/grub-core/kern/backtrace.c b/grub-core/kern/backtrace.c +new file mode 100644 +index 000000000..4a82e865c +--- /dev/null ++++ b/grub-core/kern/backtrace.c +@@ -0,0 +1,97 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static void ++grub_backtrace_print_address_default (void *addr) ++{ ++#ifndef GRUB_UTIL ++ grub_dl_t mod; ++ void *start_addr; ++ ++ FOR_DL_MODULES (mod) ++ { ++ grub_dl_segment_t segment; ++ for (segment = mod->segment; segment; segment = segment->next) ++ if (segment->addr <= addr && (grub_uint8_t *) segment->addr ++ + segment->size > (grub_uint8_t *) addr) ++ { ++ grub_printf ("%s.%x+%" PRIxGRUB_SIZE, mod->name, ++ segment->section, ++ (grub_size_t) ++ ((grub_uint8_t *)addr - (grub_uint8_t *)segment->addr)); ++ return; ++ } ++ } ++ ++ start_addr = grub_resolve_symbol ("_start"); ++ if (start_addr && start_addr < addr) ++ grub_printf ("kernel+%" PRIxGRUB_SIZE, ++ (grub_size_t) ++ ((grub_uint8_t *)addr - (grub_uint8_t *)start_addr)); ++ else ++#endif ++ grub_printf ("%p", addr); ++} ++ ++static void ++grub_backtrace_pointer_default (void *frame __attribute__((__unused__)), ++ unsigned int skip __attribute__((__unused__))) ++{ ++ return; ++} ++ ++void ++grub_backtrace_pointer (void *frame, unsigned int skip) ++ __attribute__((__weak__, ++ __alias__(("grub_backtrace_pointer_default")))); ++ ++void ++grub_backtrace_print_address (void *addr) ++ __attribute__((__weak__, ++ __alias__(("grub_backtrace_print_address_default")))); ++ ++static void ++grub_backtrace_arch_default(unsigned int skip) ++{ ++ grub_backtrace_pointer(__builtin_frame_address(0), skip + 1); ++} ++ ++void grub_backtrace_arch (unsigned int skip) ++ __attribute__((__weak__, __alias__(("grub_backtrace_arch_default")))); ++ ++void grub_backtrace (unsigned int skip) ++{ ++ grub_backtrace_arch(skip + 1); ++} ++ ++void grub_debug_backtrace (const char * const debug, ++ unsigned int skip) ++{ ++ if (grub_debug_enabled (debug)) ++ grub_backtrace (skip + 1); ++} +diff --git a/grub-core/kern/device.c b/grub-core/kern/device.c +index 670e213cf..d01963747 100644 +--- a/grub-core/kern/device.c ++++ b/grub-core/kern/device.c +@@ -34,6 +34,7 @@ grub_device_open (const char *name) + { + grub_device_t dev = 0; + ++ grub_dprintf ("device", "opening device %s\n", name); + if (! name) + { + name = grub_env_get ("root"); +diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c +index 1eda58fe9..355b6579d 100644 +--- a/grub-core/kern/disk.c ++++ b/grub-core/kern/disk.c +@@ -285,6 +285,8 @@ grub_disk_open (const char *name) + return 0; + } + ++ grub_dprintf ("disk", "Opening `%s' succeeded.\n", name); ++ + return disk; + } + +@@ -310,8 +312,10 @@ grub_disk_close (grub_disk_t disk) + grub_free (disk->partition); + disk->partition = part; + } ++ grub_dprintf ("disk", "Closing `%s' succeeded.\n", disk->name); + grub_free ((void *) disk->name); + grub_free (disk); ++ + } + + /* Small read (less than cache size and not pass across cache unit boundaries). +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 0bf40caa6..2eaef7150 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -32,12 +32,21 @@ + #include + #include + #include ++#include + + /* Platforms where modules are in a readonly area of memory. */ + #if defined(GRUB_MACHINE_QEMU) + #define GRUB_MODULES_MACHINE_READONLY + #endif + ++#ifdef GRUB_MACHINE_EMU ++#include ++#endif ++ ++#ifdef GRUB_MACHINE_EFI ++#include ++#endif ++ + + + #pragma GCC diagnostic ignored "-Wcast-align" +@@ -115,6 +124,50 @@ grub_dl_resolve_symbol (const char *name) + return 0; + } + ++void * ++grub_resolve_symbol (const char *name) ++{ ++ grub_symbol_t sym; ++ ++ sym = grub_dl_resolve_symbol (name); ++ if (sym) ++ return sym->addr; ++ return NULL; ++} ++ ++const char * ++grub_get_symbol_by_addr(const void *addr, int isfunc) ++{ ++ unsigned int i; ++ grub_symbol_t before = NULL, after = NULL; ++ for (i = 0; i < GRUB_SYMTAB_SIZE; i++) ++ { ++ grub_symbol_t sym; ++ for (sym = grub_symtab[i]; sym; sym = sym->next) ++ { ++ //grub_printf ("addr 0x%08llx symbol %s\n", (unsigned long long)sym->addr, sym->name); ++ if (sym->addr > addr) ++ { ++ if (!after || sym->addr > after->addr) ++ after = sym; ++ } ++ ++ if (isfunc != sym->isfunc) ++ continue; ++ if (sym->addr > addr) ++ continue; ++ ++ if ((!before && sym->addr <= addr) || (before && before->addr <= sym->addr)) ++ before = sym; ++ } ++ } ++ ++ if (before && addr < after->addr) ++ return before->name; ++ ++ return NULL; ++} ++ + /* Register a symbol with the name NAME and the address ADDR. */ + grub_err_t + grub_dl_register_symbol (const char *name, void *addr, int isfunc, +@@ -224,22 +277,37 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + { + unsigned i; + const Elf_Shdr *s; +- grub_size_t tsize = 0, talign = 1; ++ grub_size_t tsize = 0, talign = 1, arch_addralign = 1; + #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \ + !defined (__loongarch__) + grub_size_t tramp; ++ grub_size_t tramp_align; + grub_size_t got; ++ grub_size_t got_align; + grub_err_t err; + #endif + char *ptr; + ++ grub_dprintf ("modules", "loading segments for \"%s\"\n", mod->name); ++ ++ arch_addralign = grub_arch_dl_min_alignment (); ++ + for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) + { +- tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size; +- if (talign < s->sh_addralign) +- talign = s->sh_addralign; ++ grub_size_t sh_addralign; ++ grub_size_t sh_size; ++ ++ if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC)) ++ continue; ++ ++ sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign); ++ sh_size = ALIGN_UP(s->sh_size, sh_addralign); ++ ++ tsize = ALIGN_UP (tsize, sh_addralign) + sh_size; ++ if (talign < sh_addralign) ++ talign = sh_addralign; + } + + #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \ +@@ -247,12 +315,18 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got); + if (err) + return err; +- tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN); +- if (talign < GRUB_ARCH_DL_TRAMP_ALIGN) +- talign = GRUB_ARCH_DL_TRAMP_ALIGN; +- tsize += ALIGN_UP (got, GRUB_ARCH_DL_GOT_ALIGN); +- if (talign < GRUB_ARCH_DL_GOT_ALIGN) +- talign = GRUB_ARCH_DL_GOT_ALIGN; ++ tramp_align = GRUB_ARCH_DL_TRAMP_ALIGN; ++ if (tramp_align < arch_addralign) ++ tramp_align = arch_addralign; ++ tsize += ALIGN_UP (tramp, tramp_align); ++ if (talign < tramp_align) ++ talign = tramp_align; ++ got_align = GRUB_ARCH_DL_GOT_ALIGN; ++ if (got_align < arch_addralign) ++ got_align = arch_addralign; ++ tsize += ALIGN_UP (got, got_align); ++ if (talign < got_align) ++ talign = got_align; + #endif + + #ifdef GRUB_MACHINE_EMU +@@ -269,6 +343,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + i < e->e_shnum; + i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize)) + { ++ grub_size_t sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign); ++ grub_size_t sh_size = ALIGN_UP(s->sh_size, sh_addralign); ++ + if (s->sh_flags & SHF_ALLOC) + { + grub_dl_segment_t seg; +@@ -281,17 +358,19 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + { + void *addr; + +- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign); ++ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, sh_addralign); + addr = ptr; +- ptr += s->sh_size; ++ ptr += sh_size; + + switch (s->sh_type) + { + case SHT_PROGBITS: + grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size); ++ grub_memset ((char *)addr + s->sh_size, 0, ++ sh_size - s->sh_size); + break; + case SHT_NOBITS: +- grub_memset (addr, 0, s->sh_size); ++ grub_memset (addr, 0, sh_size); + break; + } + +@@ -300,7 +379,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + else + seg->addr = 0; + +- seg->size = s->sh_size; ++ seg->size = sh_size; + seg->section = i; + seg->next = mod->segment; + mod->segment = seg; +@@ -308,16 +387,17 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + } + #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \ + !defined (__loongarch__) +- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN); ++ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, tramp_align); + mod->tramp = ptr; + mod->trampptr = ptr; + ptr += tramp; +- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_GOT_ALIGN); ++ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, got_align); + mod->got = ptr; + mod->gotptr = ptr; + ptr += got; + #endif + ++ grub_dprintf ("modules", "done loading segments for \"%s\"\n", mod->name); + return GRUB_ERR_NONE; + } + +@@ -330,6 +410,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e) + const char *str; + Elf_Word size, entsize; + ++ grub_dprintf ("modules", "Resolving symbols for \"%s\"\n", mod->name); + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) +@@ -584,6 +665,7 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) + Elf_Shdr *s; + unsigned i; + ++ grub_dprintf ("modules", "relocating symbols for \"%s\"\n", mod->name); + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) +@@ -592,22 +674,134 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) + grub_dl_segment_t seg; + grub_err_t err; + +- /* Find the target segment. */ +- for (seg = mod->segment; seg; seg = seg->next) +- if (seg->section == s->sh_info) +- break; ++ seg = grub_dl_find_segment(mod, s->sh_info); ++ if (!seg) ++ continue; + +- if (seg) +- { +- if (!mod->symtab) +- return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); ++ if (!mod->symtab) ++ return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); + +- err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg); +- if (err) +- return err; +- } ++ err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg); ++ if (err) ++ return err; + } + ++ grub_dprintf ("modules", "done relocating symbols for \"%s\"\n", mod->name); ++ return GRUB_ERR_NONE; ++} ++ ++static void ++grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e) ++{ ++ void *text, *data = NULL; ++ long idx; ++ ++ idx = grub_dl_find_section_index (e, ".text"); ++ if (idx < 0) ++ return; ++ ++ text = grub_dl_get_section_addr (mod, idx); ++ if (!text) ++ return; ++ ++ idx = grub_dl_find_section_index (e, ".data"); ++ if (idx >= 0) ++ data = grub_dl_get_section_addr (mod, idx); ++ ++ if (data) ++ grub_qdprintf ("gdb", "add-symbol-file \\\n" ++ "/usr/lib/debug/usr/lib/grub/%s-%s/%s.debug " ++ "\\\n %p -s .data %p\n", ++ GRUB_TARGET_CPU, GRUB_PLATFORM, ++ mod->name, text, data); ++ else ++ grub_qdprintf ("gdb", "add-symbol-file \\\n" ++ "/usr/lib/debug/usr/lib/grub/%s-%s/%s.debug " ++ "\\\n%p\n", ++ GRUB_TARGET_CPU, GRUB_PLATFORM, ++ mod->name, text); ++} ++ ++static grub_err_t ++grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr) ++{ ++ unsigned i; ++ const Elf_Shdr *s; ++ const Elf_Ehdr *e = ehdr; ++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) ++ grub_size_t arch_addralign = grub_arch_dl_min_alignment (); ++ grub_addr_t tgaddr; ++ grub_size_t tgsz; ++#endif ++ ++ grub_dprintf ("modules", "updating memory attributes for \"%s\"\n", ++ mod->name); ++ for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); ++ i < e->e_shnum; ++ i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) ++ { ++ grub_dl_segment_t seg; ++ grub_uint64_t set_attrs = GRUB_MEM_ATTR_R; ++ grub_uint64_t clear_attrs = GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X; ++ ++ seg = grub_dl_find_segment(mod, i); ++ if (!seg) ++ continue; ++ ++ if (seg->size == 0 || !(s->sh_flags & SHF_ALLOC)) ++ continue; ++ ++ if (s->sh_flags & SHF_WRITE) ++ { ++ set_attrs |= GRUB_MEM_ATTR_W; ++ clear_attrs &= ~GRUB_MEM_ATTR_W; ++ } ++ ++ if (s->sh_flags & SHF_EXECINSTR) ++ { ++ set_attrs |= GRUB_MEM_ATTR_X; ++ clear_attrs &= ~GRUB_MEM_ATTR_X; ++ } ++ ++ grub_dprintf ("modules", "setting memory attrs for section \"%s\" to -%s%s%s+%s%s%s\n", ++ grub_dl_get_section_name(e, s), ++ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : ""); ++ grub_update_mem_attrs ((grub_addr_t)(seg->addr), seg->size, set_attrs, clear_attrs); ++ } ++ ++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) ++ tgaddr = grub_min((grub_addr_t)mod->tramp, (grub_addr_t)mod->got); ++ tgsz = grub_max((grub_addr_t)mod->trampptr, (grub_addr_t)mod->gotptr) - tgaddr; ++ ++ if (tgsz) ++ { ++ tgsz = ALIGN_UP(tgsz, arch_addralign); ++ ++ grub_dprintf ("modules", ++ "updating attributes for GOT and trampolines (\"%s\")\n", ++ mod->name); ++ if (tgaddr < (grub_addr_t)mod->base || ++ tgsz > (grub_addr_t)-1 - tgaddr || ++ tgaddr + tgsz > (grub_addr_t)mod->base + mod->sz) ++ return grub_error (GRUB_ERR_BUG, ++ "BUG: trying to protect pages outside of module " ++ "allocation (\"%s\"): module base %p, size 0x%" ++ PRIxGRUB_SIZE "; tramp/GOT base 0x%" PRIxGRUB_ADDR ++ ", size 0x%" PRIxGRUB_SIZE, ++ mod->name, mod->base, mod->sz, tgaddr, tgsz); ++ grub_update_mem_attrs (tgaddr, tgsz, GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_X, ++ GRUB_MEM_ATTR_W); ++ } ++#endif ++ ++ grub_dprintf ("modules", "done updating module memory attributes for \"%s\"\n", ++ mod->name); ++ + return GRUB_ERR_NONE; + } + +@@ -644,6 +838,7 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) + mod->ref_count = 1; + + grub_dprintf ("modules", "relocating to %p\n", mod); ++ + /* Me, Vladimir Serbinenko, hereby I add this module check as per new + GNU module policy. Note that this license check is informative only. + Modules have to be licensed under GPLv3 or GPLv3+ (optionally +@@ -657,7 +852,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) + || grub_dl_resolve_dependencies (mod, e) + || grub_dl_load_segments (mod, e) + || grub_dl_resolve_symbols (mod, e) +- || grub_dl_relocate_symbols (mod, e)) ++ || grub_dl_relocate_symbols (mod, e) ++ || grub_dl_set_mem_attrs (mod, e)) + { + mod->fini = 0; + grub_dl_unload (mod); +@@ -669,6 +865,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) + grub_dprintf ("modules", "module name: %s\n", mod->name); + grub_dprintf ("modules", "init function: %p\n", mod->init); + ++ grub_dl_print_gdb_info (mod, e); ++ + if (grub_dl_add (mod)) + { + grub_dl_unload (mod); +@@ -706,6 +904,19 @@ grub_dl_load_file (const char *filename) + void *core = 0; + grub_dl_t mod = 0; + ++#ifdef GRUB_MACHINE_EFI ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ { ++#if 0 ++ /* This is an error, but grub2-mkconfig still generates a pile of ++ * insmod commands, so emitting it would be mostly just obnoxious. */ ++ grub_error (GRUB_ERR_ACCESS_DENIED, ++ "Secure Boot forbids loading module from %s", filename); ++#endif ++ return 0; ++ } ++#endif ++ + grub_boot_time ("Loading module %s", filename); + + file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE); +diff --git a/grub-core/kern/efi/debug.c b/grub-core/kern/efi/debug.c +index 5d2ab1a36..5ac194fc8 100644 +--- a/grub-core/kern/efi/debug.c ++++ b/grub-core/kern/efi/debug.c +@@ -26,7 +26,7 @@ grub_cmd_gdbinfo (struct grub_command *cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) + { +- grub_efi_print_gdb_info (); ++ grub_efi_print_gdb_info (false); + return 0; + } + +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index b93ae3aba..b5b8a3296 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -96,6 +96,19 @@ grub_efi_locate_handle (grub_efi_locate_search_type_t search_type, + return buffer; + } + ++grub_efi_status_t ++grub_efi_connect_controller (grub_efi_handle_t controller_handle, ++ grub_efi_handle_t *driver_image_handle, ++ grub_efi_device_path_protocol_t *remaining_device_path, ++ grub_efi_boolean_t recursive) ++{ ++ grub_efi_boot_services_t *b; ++ ++ b = grub_efi_system_table->boot_services; ++ return b->connect_controller(controller_handle, ++ driver_image_handle, remaining_device_path, recursive); ++} ++ + void * + grub_efi_open_protocol (grub_efi_handle_t handle, + grub_guid_t *protocol, +@@ -175,11 +188,16 @@ grub_reboot (void) + } + + void +-grub_exit (void) ++grub_exit (int retval) + { ++ grub_efi_status_t rc = GRUB_EFI_LOAD_ERROR; ++ ++ if (retval == 0) ++ rc = GRUB_EFI_SUCCESS; ++ + grub_machine_fini (GRUB_LOADER_FLAG_NORETURN); + grub_efi_system_table->boot_services->exit (grub_efi_image_handle, +- GRUB_EFI_SUCCESS, 0, 0); ++ rc, 0, 0); + for (;;) ; + } + +@@ -222,6 +240,9 @@ grub_efi_set_variable_with_attributes (const char *var, const grub_guid_t *guid, + if (status == GRUB_EFI_SUCCESS) + return GRUB_ERR_NONE; + ++ if (status == GRUB_EFI_NOT_FOUND && datasize == 0) ++ return GRUB_ERR_NONE; ++ + return grub_error (GRUB_ERR_IO, "could not set EFI variable `%s'", var); + } + +@@ -770,7 +791,7 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) + { + grub_efi_ipv4_device_path_t *ipv4 + = (grub_efi_ipv4_device_path_t *) dp; +- grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x)", ++ grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x", + (unsigned) ipv4->local_ip_address[0], + (unsigned) ipv4->local_ip_address[1], + (unsigned) ipv4->local_ip_address[2], +@@ -783,33 +804,60 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) + (unsigned) ipv4->remote_port, + (unsigned) ipv4->protocol, + (unsigned) ipv4->static_ip_address); ++ if (len == sizeof (*ipv4)) ++ { ++ grub_printf (",%u.%u.%u.%u,%u.%u.%u.%u", ++ (unsigned) ipv4->gateway_ip_address[0], ++ (unsigned) ipv4->gateway_ip_address[1], ++ (unsigned) ipv4->gateway_ip_address[2], ++ (unsigned) ipv4->gateway_ip_address[3], ++ (unsigned) ipv4->subnet_mask[0], ++ (unsigned) ipv4->subnet_mask[1], ++ (unsigned) ipv4->subnet_mask[2], ++ (unsigned) ipv4->subnet_mask[3]); ++ } ++ grub_printf (")"); + } + break; + case GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE: + { + grub_efi_ipv6_device_path_t *ipv6 + = (grub_efi_ipv6_device_path_t *) dp; +- grub_printf ("/IPv6(%x:%x:%x:%x:%x:%x:%x:%x,%x:%x:%x:%x:%x:%x:%x:%x,%u,%u,%x,%x)", +- (unsigned) ipv6->local_ip_address[0], +- (unsigned) ipv6->local_ip_address[1], +- (unsigned) ipv6->local_ip_address[2], +- (unsigned) ipv6->local_ip_address[3], +- (unsigned) ipv6->local_ip_address[4], +- (unsigned) ipv6->local_ip_address[5], +- (unsigned) ipv6->local_ip_address[6], +- (unsigned) ipv6->local_ip_address[7], +- (unsigned) ipv6->remote_ip_address[0], +- (unsigned) ipv6->remote_ip_address[1], +- (unsigned) ipv6->remote_ip_address[2], +- (unsigned) ipv6->remote_ip_address[3], +- (unsigned) ipv6->remote_ip_address[4], +- (unsigned) ipv6->remote_ip_address[5], +- (unsigned) ipv6->remote_ip_address[6], +- (unsigned) ipv6->remote_ip_address[7], ++ grub_printf ("/IPv6(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%u,%u,%x,%x", ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[0]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[1]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[2]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[3]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[4]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[5]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[6]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[7]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[0]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[1]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[2]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[3]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[4]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[5]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[6]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[7]), + (unsigned) ipv6->local_port, + (unsigned) ipv6->remote_port, + (unsigned) ipv6->protocol, + (unsigned) ipv6->static_ip_address); ++ if (len == sizeof (*ipv6)) ++ { ++ grub_printf (",%u,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", ++ (unsigned) ipv6->prefix_length, ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[0]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[1]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[2]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[3]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[4]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[5]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[6]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[7])); ++ } ++ grub_printf (")"); + } + break; + case GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE: +@@ -856,6 +904,39 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) + dump_vendor_path ("Messaging", + (grub_efi_vendor_device_path_t *) dp); + break; ++ case GRUB_EFI_URI_DEVICE_PATH_SUBTYPE: ++ { ++ grub_efi_uri_device_path_t *uri ++ = (grub_efi_uri_device_path_t *) dp; ++ grub_printf ("/URI(%s)", uri->uri); ++ } ++ break; ++ case GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE: ++ { ++ grub_efi_dns_device_path_t *dns ++ = (grub_efi_dns_device_path_t *) dp; ++ if (dns->is_ipv6) ++ { ++ grub_printf ("/DNS(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x)", ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0])), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1])), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2])), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]))); ++ } ++ else ++ { ++ grub_printf ("/DNS(%d.%d.%d.%d)", ++ dns->dns_server_ip[0].v4.addr[0], ++ dns->dns_server_ip[0].v4.addr[1], ++ dns->dns_server_ip[0].v4.addr[2], ++ dns->dns_server_ip[0].v4.addr[3]); ++ } ++ } ++ break; + default: + grub_printf ("/UnknownMessaging(%x)", (unsigned) subtype); + break; +@@ -1049,3 +1130,96 @@ grub_efi_find_configuration_table (const grub_guid_t *target_guid) + + return 0; + } ++ ++static const grub_efi_loader_t *override_loader = NULL; ++ ++grub_err_t ++grub_efi_register_loader (const grub_efi_loader_t *loader) ++{ ++ if (override_loader != NULL) ++ return grub_error (GRUB_ERR_BUG, "trying to register different loader"); ++ override_loader = loader; ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_efi_unregister_loader (const grub_efi_loader_t *loader) ++{ ++ if (loader != override_loader) ++ return grub_error (GRUB_ERR_BUG, "trying to unregister different loader"); ++ ++ override_loader = NULL; ++ return GRUB_ERR_NONE; ++} ++ ++grub_efi_status_t ++grub_efi_load_image (grub_efi_boolean_t boot_policy, ++ grub_efi_handle_t parent_image_handle, ++ grub_efi_device_path_t *file_path, void *source_buffer, ++ grub_efi_uintn_t source_size, ++ grub_efi_handle_t *image_handle) ++{ ++ if (override_loader != NULL) ++ return override_loader->load_image (boot_policy, parent_image_handle, ++ file_path, source_buffer, source_size, ++ image_handle); ++ return grub_efi_system_table->boot_services->load_image ( ++ boot_policy, parent_image_handle, file_path, source_buffer, source_size, ++ image_handle); ++} ++ ++grub_efi_status_t ++grub_efi_start_image (grub_efi_handle_t image_handle, ++ grub_efi_uintn_t *exit_data_size, ++ grub_efi_char16_t **exit_data) ++{ ++ if (override_loader != NULL) ++ return override_loader->start_image (image_handle, exit_data_size, ++ exit_data); ++ return grub_efi_system_table->boot_services->start_image ( ++ image_handle, exit_data_size, exit_data); ++} ++ ++grub_efi_status_t ++grub_efi_unload_image (grub_efi_handle_t image_handle) ++{ ++ if (override_loader != NULL) ++ return override_loader->unload_image (image_handle); ++ return grub_efi_system_table->boot_services->unload_image (image_handle); ++} ++ ++grub_err_t ++grub_efi_status_to_err (grub_efi_status_t status) ++{ ++ grub_err_t err; ++ switch (status) ++ { ++ case GRUB_EFI_SUCCESS: ++ err = GRUB_ERR_NONE; ++ break; ++ case GRUB_EFI_INVALID_PARAMETER: ++ default: ++ err = GRUB_ERR_BAD_ARGUMENT; ++ break; ++ case GRUB_EFI_OUT_OF_RESOURCES: ++ err = GRUB_ERR_OUT_OF_MEMORY; ++ break; ++ case GRUB_EFI_DEVICE_ERROR: ++ err = GRUB_ERR_IO; ++ break; ++ case GRUB_EFI_WRITE_PROTECTED: ++ err = GRUB_ERR_WRITE_ERROR; ++ break; ++ case GRUB_EFI_SECURITY_VIOLATION: ++ err = GRUB_ERR_ACCESS_DENIED; ++ break; ++ case GRUB_EFI_NOT_FOUND: ++ err = GRUB_ERR_FILE_NOT_FOUND; ++ break; ++ case GRUB_EFI_ABORTED: ++ err = GRUB_ERR_WAIT; ++ break; ++ } ++ ++ return err; ++} +diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c +index 6c54af6e7..ce8a7fe71 100644 +--- a/grub-core/kern/efi/init.c ++++ b/grub-core/kern/efi/init.c +@@ -28,8 +28,11 @@ + #include + #include + #include ++ + #include + ++#include ++ + #ifdef GRUB_STACK_PROTECTOR + + static grub_efi_char16_t stack_chk_fail_msg[] = +@@ -103,6 +106,31 @@ stack_protector_init (void) + + grub_addr_t grub_modbase; + ++/* Helper for grub_efi_env_init */ ++static int ++set_var (const char *name, const char *value, ++ void *whitelist __attribute__((__unused__))) ++{ ++ grub_env_set (name, value); ++ return 0; ++} ++ ++static void ++grub_efi_env_init (void) ++{ ++ grub_guid_t efi_grub_guid = GRUB_EFI_GRUB_VARIABLE_GUID; ++ struct grub_envblk envblk_s = { NULL, 0 }; ++ grub_envblk_t envblk = &envblk_s; ++ ++ grub_efi_get_variable ("GRUB_ENV", &efi_grub_guid, &envblk_s.size, ++ (void **) &envblk_s.buf); ++ if (!envblk_s.buf || envblk_s.size < 1) ++ return; ++ ++ grub_envblk_iterate (envblk, NULL, set_var); ++ grub_free (envblk_s.buf); ++} ++ + __attribute__ ((__optimize__ ("-fno-stack-protector"))) void + grub_efi_init (void) + { +@@ -128,6 +156,8 @@ grub_efi_init (void) + + grub_efi_system_table->boot_services->set_watchdog_timer (0, 0, 0, NULL); + ++ grub_efi_env_init (); ++ grub_efi_print_gdb_info (true); + grub_efidisk_init (); + + grub_efi_register_debug_commands (); +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 6a6fba891..464fe1c3c 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -112,6 +112,38 @@ grub_efi_drop_alloc (grub_efi_physical_address_t address, + } + } + ++/* Allocate pages below a specified address */ ++void * ++grub_efi_allocate_pages_max (grub_efi_physical_address_t max, ++ grub_efi_uintn_t pages) ++{ ++ grub_efi_status_t status; ++ grub_efi_boot_services_t *b; ++ grub_efi_physical_address_t address = max; ++ ++ if (max > GRUB_EFI_MAX_USABLE_ADDRESS) ++ return 0; ++ ++ b = grub_efi_system_table->boot_services; ++ status = b->allocate_pages (GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ if (address == 0) ++ { ++ /* Uggh, the address 0 was allocated... This is too annoying, ++ so reallocate another one. */ ++ address = max; ++ status = b->allocate_pages (GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address); ++ grub_efi_free_pages (0, pages); ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ } ++ ++ return (void *) ((grub_addr_t) address); ++} ++ + /* Allocate pages. Return the pointer to the first of allocated pages. */ + void * + grub_efi_allocate_pages_real (grub_efi_physical_address_t address, +@@ -121,8 +153,9 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + { + grub_efi_status_t status; + grub_efi_boot_services_t *b; ++ grub_efi_physical_address_t ret = address; + +- /* Limit the memory access to less than 4GB for 32-bit platforms. */ ++/* Limit the memory access to less than 4GB for 32-bit platforms. */ + if (address > GRUB_EFI_MAX_USABLE_ADDRESS) + { + char inv_addr[17], max_addr[17]; /* log16(2^64) = 16, plus NUL. */ +@@ -137,19 +170,22 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + } + + b = grub_efi_system_table->boot_services; +- status = b->allocate_pages (alloctype, memtype, pages, &address); ++ status = b->allocate_pages (alloctype, memtype, pages, &ret); + if (status != GRUB_EFI_SUCCESS) + { ++ grub_dprintf ("efi", ++ "allocate_pages(%d, %d, 0x%0lx, 0x%016lx) = 0x%016lx\n", ++ alloctype, memtype, pages, address, status); + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + return NULL; + } + +- if (address == 0) ++ if (ret == 0) + { + /* Uggh, the address 0 was allocated... This is too annoying, + so reallocate another one. */ +- address = GRUB_EFI_MAX_USABLE_ADDRESS; +- status = b->allocate_pages (alloctype, memtype, pages, &address); ++ ret = address; ++ status = b->allocate_pages (alloctype, memtype, pages, &ret); + grub_efi_free_pages (0, pages); + if (status != GRUB_EFI_SUCCESS) + { +@@ -158,9 +194,9 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + } + } + +- grub_efi_store_alloc (address, pages); ++ grub_efi_store_alloc (ret, pages); + +- return (void *) ((grub_addr_t) address); ++ return (void *) ((grub_addr_t) ret); + } + + void * +@@ -445,7 +481,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + { + if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY + #if 1 +- && desc->physical_start <= GRUB_EFI_MAX_USABLE_ADDRESS ++ && desc->physical_start <= GRUB_EFI_MAX_ALLOCATION_ADDRESS + #endif + && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000 + && desc->num_pages != 0) +@@ -463,9 +499,9 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + #if 1 + if (BYTES_TO_PAGES (filtered_desc->physical_start) + + filtered_desc->num_pages +- > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS)) ++ > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS)) + filtered_desc->num_pages +- = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS) ++ = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS) + - BYTES_TO_PAGES (filtered_desc->physical_start)); + #endif + +@@ -567,6 +603,83 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map, + } + #endif + ++grub_addr_t grub_stack_addr = (grub_addr_t)-1ll; ++grub_size_t grub_stack_size = 0; ++ ++static void ++grub_nx_init (void) ++{ ++ grub_uint64_t attrs, stack_attrs; ++ grub_err_t err; ++ grub_addr_t stack_current, stack_end; ++ const grub_uint64_t page_size = 4096; ++ const grub_uint64_t page_mask = ~(page_size - 1); ++ ++ /* ++ * These are to confirm that the flags are working as expected when ++ * debugging. ++ */ ++ attrs = 0; ++ stack_current = (grub_addr_t)grub_nx_init & page_mask; ++ err = grub_get_mem_attrs (stack_current, page_size, &attrs); ++ if (err) ++ { ++ grub_dprintf ("nx", ++ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n", ++ stack_current, err); ++ grub_error_pop (); ++ } ++ else ++ grub_dprintf ("nx", "page attrs for grub_nx_init (%p) are %c%c%c\n", ++ grub_dl_load_core, ++ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-'); ++ ++ stack_current = (grub_addr_t)&stack_current & page_mask; ++ err = grub_get_mem_attrs (stack_current, page_size, &stack_attrs); ++ if (err) ++ { ++ grub_dprintf ("nx", ++ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n", ++ stack_current, err); ++ grub_error_pop (); ++ } ++ else ++ { ++ attrs = stack_attrs; ++ grub_dprintf ("nx", "page attrs for stack (%p) are %c%c%c\n", ++ &attrs, ++ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-'); ++ } ++ for (stack_end = stack_current + page_size ; ++ !(attrs & GRUB_MEM_ATTR_R); ++ stack_end += page_size) ++ { ++ err = grub_get_mem_attrs (stack_current, page_size, &attrs); ++ if (err) ++ { ++ grub_dprintf ("nx", ++ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n", ++ stack_current, err); ++ grub_error_pop (); ++ break; ++ } ++ } ++ if (stack_end > stack_current) ++ { ++ grub_stack_addr = stack_current; ++ grub_stack_size = stack_end - stack_current; ++ grub_dprintf ("nx", ++ "detected stack from 0x%"PRIxGRUB_ADDR" to 0x%"PRIxGRUB_ADDR"\n", ++ grub_stack_addr, grub_stack_addr + grub_stack_size - 1); ++ } ++} ++ ++ ++ + static grub_err_t + grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags) + { +@@ -579,6 +692,8 @@ grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags) + grub_err_t err; + int mm_status; + ++ grub_nx_init (); ++ + /* Prepare a memory region to store two memory maps. */ + memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + if (! memory_map) +@@ -679,11 +794,155 @@ grub_efi_get_ram_base(grub_addr_t *base_addr) + for (desc = memory_map, *base_addr = GRUB_EFI_MAX_USABLE_ADDRESS; + (grub_addr_t) desc < ((grub_addr_t) memory_map + memory_map_size); + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) +- if (desc->attribute & GRUB_EFI_MEMORY_WB) +- *base_addr = grub_min (*base_addr, desc->physical_start); ++ { ++ if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY && ++ (desc->attribute & GRUB_EFI_MEMORY_WB)) ++ { ++ *base_addr = grub_min (*base_addr, desc->physical_start); ++ grub_dprintf ("efi", "setting base_addr=0x%016lx\n", *base_addr); ++ } ++ else ++ { ++ grub_dprintf ("efi", "ignoring address 0x%016lx\n", desc->physical_start); ++ } ++ } ++ ++ if (*base_addr == GRUB_EFI_MAX_USABLE_ADDRESS) ++ grub_dprintf ("efi", "base_addr 0x%016lx is probably wrong.\n", *base_addr); + + grub_free(memory_map); + + return GRUB_ERR_NONE; + } + #endif ++ ++static inline grub_uint64_t ++grub_mem_attrs_to_uefi_mem_attrs (grub_uint64_t attrs) ++{ ++ grub_uint64_t ret = GRUB_EFI_MEMORY_RP | ++ GRUB_EFI_MEMORY_RO | ++ GRUB_EFI_MEMORY_XP; ++ ++ if (attrs & GRUB_MEM_ATTR_R) ++ ret &= ~GRUB_EFI_MEMORY_RP; ++ ++ if (attrs & GRUB_MEM_ATTR_W) ++ ret &= ~GRUB_EFI_MEMORY_RO; ++ ++ if (attrs & GRUB_MEM_ATTR_X) ++ ret &= ~GRUB_EFI_MEMORY_XP; ++ ++ return ret; ++} ++ ++static inline grub_uint64_t ++uefi_mem_attrs_to_grub_mem_attrs (grub_uint64_t attrs) ++{ ++ grub_uint64_t ret = GRUB_MEM_ATTR_R | ++ GRUB_MEM_ATTR_W | ++ GRUB_MEM_ATTR_X; ++ ++ if (attrs & GRUB_EFI_MEMORY_RP) ++ ret &= ~GRUB_MEM_ATTR_R; ++ ++ if (attrs & GRUB_EFI_MEMORY_RO) ++ ret &= ~GRUB_MEM_ATTR_W; ++ ++ if (attrs & GRUB_EFI_MEMORY_XP) ++ ret &= ~GRUB_MEM_ATTR_X; ++ ++ return ret; ++} ++ ++grub_err_t ++grub_get_mem_attrs (grub_addr_t addr, grub_size_t size, grub_uint64_t *attrs) ++{ ++ grub_efi_memory_attribute_protocol_t *proto; ++ grub_efi_physical_address_t physaddr = addr; ++ grub_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; ++ grub_efi_status_t efi_status; ++ ++ proto = grub_efi_locate_protocol (&protocol_guid, 0); ++ if (!proto) ++ return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ ++ if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL) ++ { ++ grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" and attrs %p\n", ++ __func__, physaddr, physaddr+size-1, attrs); ++ return 0; ++ } ++ ++ efi_status = proto->get_memory_attributes( ++ proto, physaddr, size, attrs); ++ *attrs = uefi_mem_attrs_to_grub_mem_attrs (*attrs); ++ ++ return grub_efi_status_to_err (efi_status); ++} ++ ++grub_err_t ++grub_update_mem_attrs (grub_addr_t addr, grub_size_t size, ++ grub_uint64_t set_attrs, grub_uint64_t clear_attrs) ++{ ++ grub_efi_memory_attribute_protocol_t *proto; ++ grub_efi_physical_address_t physaddr = addr; ++ grub_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; ++ grub_efi_status_t efi_status = GRUB_EFI_SUCCESS; ++ grub_uint64_t before = 0, after = 0, uefi_set_attrs, uefi_clear_attrs; ++ grub_err_t err; ++ ++ proto = grub_efi_locate_protocol (&protocol_guid, 0); ++ if (!proto) ++ return GRUB_ERR_NONE; ++ ++ err = grub_get_mem_attrs (addr, size, &before); ++ if (err) ++ grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n", ++ addr, size, &before, err); ++ ++ if (physaddr & 0xfff || size & 0xfff || size == 0) ++ { ++ grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" +%s%s%s -%s%s%s\n", ++ __func__, physaddr, physaddr + size - 1, ++ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : ""); ++ return 0; ++ } ++ ++ uefi_set_attrs = grub_mem_attrs_to_uefi_mem_attrs (set_attrs); ++ grub_dprintf ("nx", "translating set_attrs from 0x%lx to 0x%lx\n", set_attrs, uefi_set_attrs); ++ uefi_clear_attrs = grub_mem_attrs_to_uefi_mem_attrs (clear_attrs); ++ grub_dprintf ("nx", "translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs, uefi_clear_attrs); ++ if (uefi_set_attrs) ++ efi_status = proto->set_memory_attributes( ++ proto, physaddr, size, uefi_set_attrs); ++ if (efi_status == GRUB_EFI_SUCCESS && uefi_clear_attrs) ++ efi_status = proto->clear_memory_attributes( ++ proto, physaddr, size, uefi_clear_attrs); ++ ++ err = grub_get_mem_attrs (addr, size, &after); ++ if (err) ++ grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n", ++ addr, size, &after, err); ++ ++ grub_dprintf ("nx", "set +%s%s%s -%s%s%s on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" before:%c%c%c after:%c%c%c\n", ++ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ addr, addr + size - 1, ++ (before & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (before & GRUB_MEM_ATTR_W) ? 'w' : '-', ++ (before & GRUB_MEM_ATTR_X) ? 'x' : '-', ++ (after & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (after & GRUB_MEM_ATTR_W) ? 'w' : '-', ++ (after & GRUB_MEM_ATTR_X) ? 'x' : '-'); ++ ++ return grub_efi_status_to_err (efi_status); ++} +diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c +index e8d63b1f5..1de1c28eb 100644 +--- a/grub-core/kern/emu/full.c ++++ b/grub-core/kern/emu/full.c +@@ -67,3 +67,16 @@ grub_arch_dl_init_linker (void) + } + #endif + ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c +index 855b11c3d..61b318177 100644 +--- a/grub-core/kern/emu/main.c ++++ b/grub-core/kern/emu/main.c +@@ -67,7 +67,7 @@ grub_reboot (void) + } + + void +-grub_exit (void) ++grub_exit (int retval __attribute__((unused))) + { + grub_reboot (); + } +@@ -108,6 +108,7 @@ static struct argp_option options[] = { + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + {"hold", 'H', N_("SECS"), OPTION_ARG_OPTIONAL, N_("wait until a debugger will attach"), 0}, + {"kexec", 'X', 0, 0, N_("use kexec to boot Linux kernels via systemctl (pass twice to enable dangerous fallback to non-systemctl)."), 0}, ++ {"switch-root", 'W', 0, 0, N_("use switch-root to only switch root filesystem without restarting the kernel."), 0}, + { 0, 0, 0, 0, 0, 0 } + }; + +@@ -168,7 +169,9 @@ argp_parser (int key, char *arg, struct argp_state *state) + case 'X': + grub_util_set_kexecute (); + break; +- ++ case 'W': ++ grub_util_set_switch_root (); ++ break; + case ARGP_KEY_ARG: + { + /* Too many arguments. */ +diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c +index 521220b49..7b9731b7e 100644 +--- a/grub-core/kern/emu/misc.c ++++ b/grub-core/kern/emu/misc.c +@@ -40,6 +40,7 @@ + + int verbosity; + int kexecute; ++int switchroot = 0; + + void + grub_util_warn (const char *fmt, ...) +@@ -83,7 +84,7 @@ grub_util_error (const char *fmt, ...) + vfprintf (stderr, fmt, ap); + va_end (ap); + fprintf (stderr, ".\n"); +- grub_exit (); ++ grub_exit (1); + } + + void * +@@ -152,12 +153,13 @@ xasprintf (const char *fmt, ...) + + #if !defined (GRUB_MACHINE_EMU) || defined (GRUB_UTIL) + void +-grub_exit (void) ++__attribute__ ((noreturn)) ++grub_exit (int rc) + { +-#if defined (GRUB_KERNEL) ++#if defined (GRUB_KERNEL) && !defined (GRUB_MACHINE_EFI) + grub_reboot (); + #endif +- exit (1); ++ exit (rc < 0 ? 1 : rc); + } + #endif + +@@ -188,7 +190,7 @@ grub_util_get_image_size (const char *path) + sz = ftello (f); + if (sz < 0) + grub_util_error (_("cannot open `%s': %s"), path, strerror (errno)); +- if (sz != (size_t) sz) ++ if (sz > (off_t)(GRUB_SIZE_MAX >> 1)) + grub_util_error (_("file `%s' is too big"), path); + ret = (size_t) sz; + +@@ -230,3 +232,15 @@ grub_util_get_kexecute (void) + { + return kexecute; + } ++ ++void ++grub_util_set_switch_root (void) ++{ ++ switchroot = 1; ++} ++ ++int ++grub_util_get_switch_root (void) ++{ ++ return switchroot; ++} +diff --git a/grub-core/kern/err.c b/grub-core/kern/err.c +index 53c734de7..aebfe0cf8 100644 +--- a/grub-core/kern/err.c ++++ b/grub-core/kern/err.c +@@ -33,15 +33,24 @@ static struct grub_error_saved grub_error_stack_items[GRUB_ERROR_STACK_SIZE]; + static int grub_error_stack_pos; + static int grub_error_stack_assert; + ++#ifdef grub_error ++#undef grub_error ++#endif ++ + grub_err_t +-grub_error (grub_err_t n, const char *fmt, ...) ++grub_error (grub_err_t n, const char *file, const int line, const char *fmt, ...) + { + va_list ap; ++ int m; + + grub_errno = n; + ++ m = grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "%s:%d:", file, line); ++ if (m < 0) ++ m = 0; ++ + va_start (ap, fmt); +- grub_vsnprintf (grub_errmsg, sizeof (grub_errmsg), _(fmt), ap); ++ grub_vsnprintf (grub_errmsg + m, sizeof (grub_errmsg) - m, _(fmt), ap); + va_end (ap); + + return n; +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index 750177248..75510df7c 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -30,6 +30,14 @@ void (*EXPORT_VAR (grub_grubnet_fini)) (void); + + grub_file_filter_t grub_file_filters[GRUB_FILE_FILTER_MAX]; + ++static const char *filter_names[] = { ++ [GRUB_FILE_FILTER_VERIFY] = "GRUB_FILE_FILTER_VERIFY", ++ [GRUB_FILE_FILTER_GZIO] = "GRUB_FILE_FILTER_GZIO", ++ [GRUB_FILE_FILTER_XZIO] = "GRUB_FILE_FILTER_XZIO", ++ [GRUB_FILE_FILTER_LZOPIO] = "GRUB_FILE_FILTER_LZOPIO", ++ [GRUB_FILE_FILTER_MAX] = "GRUB_FILE_FILTER_MAX" ++}; ++ + /* Get the device part of the filename NAME. It is enclosed by parentheses. */ + char * + grub_file_get_device_name (const char *name) +@@ -66,6 +74,8 @@ grub_file_open (const char *name, enum grub_file_type type) + const char *file_name; + grub_file_filter_id_t filter; + ++ grub_dprintf ("file", "Opening `%s' ...\n", name); ++ + /* Reset grub_errno before we start. */ + grub_errno = GRUB_ERR_NONE; + +@@ -122,6 +132,9 @@ grub_file_open (const char *name, enum grub_file_type type) + if (grub_file_filters[filter]) + { + last_file = file; ++ if (filter < GRUB_FILE_FILTER_MAX) ++ grub_dprintf ("file", "Running %s file filter\n", ++ filter_names[filter]); + file = grub_file_filters[filter] (file, type); + if (file && file != last_file) + { +@@ -132,6 +145,8 @@ grub_file_open (const char *name, enum grub_file_type type) + if (!file) + grub_file_close (last_file); + ++ grub_dprintf ("file", "Opening `%s' succeeded.\n", name); ++ + return file; + + fail: +@@ -143,6 +158,8 @@ grub_file_open (const char *name, enum grub_file_type type) + + grub_free (file); + ++ grub_dprintf ("file", "Opening `%s' failed.\n", name); ++ + return 0; + } + +@@ -155,25 +172,30 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) + grub_disk_read_hook_t read_hook; + void *read_hook_data; + +- if (file->offset > file->size) +- { +- grub_error (GRUB_ERR_OUT_OF_RANGE, +- N_("attempt to read past the end of file")); +- return -1; +- } +- + if (len == 0) + return 0; + +- if (len > file->size - file->offset) +- len = file->size - file->offset; ++#ifdef GRUB_MACHINE_EMU ++ if (file->size >= 0) ++ { ++#endif ++ if (file->offset > file->size) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("attempt to read past the end of file")); ++ return -1; ++ } ++ ++ if (len > file->size - file->offset) ++ len = file->size - file->offset; ++#ifdef GRUB_MACHINE_EMU ++ } ++#endif + + /* Prevent an overflow. */ + if ((grub_ssize_t) len < 0) + len >>= 1; + +- if (len == 0) +- return 0; + read_hook = file->read_hook; + read_hook_data = file->read_hook_data; + if (!file->read_hook) +@@ -194,11 +216,18 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) + grub_err_t + grub_file_close (grub_file_t file) + { ++ grub_dprintf ("file", "Closing `%s' ...\n", file->name); + if (file->fs->fs_close) + (file->fs->fs_close) (file); + + if (file->device) + grub_device_close (file->device); ++ ++ if (grub_errno == GRUB_ERR_NONE) ++ grub_dprintf ("file", "Closing `%s' succeeded.\n", file->name); ++ else ++ grub_dprintf ("file", "Closing `%s' failed with %d.\n", file->name, grub_errno); ++ + grub_free (file->name); + grub_free (file); + return grub_errno; +diff --git a/grub-core/kern/fs.c b/grub-core/kern/fs.c +index 7ad0aaf4e..f25bace62 100644 +--- a/grub-core/kern/fs.c ++++ b/grub-core/kern/fs.c +@@ -74,6 +74,7 @@ grub_fs_probe (grub_device_t device) + if (grub_errno == GRUB_ERR_NONE) + return p; + ++ grub_dprintf ("fs", _("error: %s.\n"), grub_errmsg); + grub_error_push (); + /* The grub_error_push() does not touch grub_errmsg. */ + grub_dprintf ("fs", _("error: %s.\n"), grub_errmsg); +diff --git a/grub-core/kern/i386/backtrace.c b/grub-core/kern/i386/backtrace.c +new file mode 100644 +index 000000000..2413f9a57 +--- /dev/null ++++ b/grub-core/kern/i386/backtrace.c +@@ -0,0 +1,125 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_STACK_FRAME 102400 ++ ++void ++grub_backtrace_pointer (void *frame, unsigned int skip) ++{ ++ void **ebp = (void **)frame; ++ unsigned long x = 0; ++ ++ while (ebp) ++ { ++ void **next_ebp = (void **)ebp[0]; ++ const char *name = NULL; ++ char *addr = NULL; ++ ++ grub_dprintf("backtrace", "ebp is %p next_ebp is %p\n", ebp, next_ebp); ++ ++ if (x >= skip) ++ { ++ name = grub_get_symbol_by_addr (ebp[1], 1); ++ if (name) ++ addr = grub_resolve_symbol (name); ++ grub_backtrace_print_address (ebp[1]); ++ ++ if (addr && addr != ebp[1]) ++ grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr, ++ (char *)((char *)ebp[1] - addr)); ++ else ++ grub_printf(" %s() %p \n", name ? name : "unknown", addr); ++ ++#if 0 ++ grub_printf ("("); ++ for (i = 0, arg = ebp[2]; arg != next_ebp && i < 12; arg++, i++) ++ grub_printf ("%p,", arg); ++ grub_printf (")\n"); ++#endif ++ } ++ ++ x += 1; ++ ++ if (next_ebp < ebp || next_ebp - ebp > MAX_STACK_FRAME || next_ebp == ebp) ++ { ++ //grub_printf ("Invalid stack frame at %p (%p)\n", ebp, next_ebp); ++ break; ++ } ++ ebp = next_ebp; ++ } ++} ++ ++#if defined (__x86_64__) ++asm ("\t.global \"_text\"\n" ++ "_text:\n" ++ "\t.quad .text\n" ++ "\t.global \"_data\"\n" ++ "_data:\n" ++ "\t.quad .data\n" ++ ); ++#elif defined(__i386__) ++asm ("\t.global \"_text\"\n" ++ "_text:\n" ++ "\t.long .text\n" ++ "\t.global \"_data\"\n" ++ "_data:\n" ++ "\t.long .data\n" ++ ); ++#else ++#warning I dunno... ++#endif ++ ++extern unsigned long _text; ++extern unsigned long _data; ++ ++#ifdef GRUB_UTIL ++#define EXT_C(x) x ++#endif ++ ++void ++grub_backtrace_arch (unsigned int skip) ++{ ++ grub_printf ("Backtrace (.text %p .data %p):\n", ++ (void *)_text, (void *)_data); ++ skip += 1; ++#if defined (__x86_64__) ++ asm volatile ("movq %%rbp, %%rdi\n" ++ "movq 0, %%rsi\n" ++ "movl %0, %%esi\n" ++ "call " EXT_C("grub_backtrace_pointer") ++ : ++ : "r" (skip)); ++#elif defined(__i386__) ++ asm volatile ("addl $8, %%esp\n" ++ "pushl %0\n" ++ "pushl %%ebp\n" ++ "call " EXT_C("grub_backtrace_pointer") ++ : ++ : "r" (skip)); ++#else ++ grub_backtrace_pointer(__builtin_frame_address(0), skip); ++#endif ++} +diff --git a/grub-core/kern/i386/coreboot/init.c b/grub-core/kern/i386/coreboot/init.c +index 4fae8b571..feaf9295e 100644 +--- a/grub-core/kern/i386/coreboot/init.c ++++ b/grub-core/kern/i386/coreboot/init.c +@@ -41,7 +41,7 @@ extern grub_uint8_t _end[]; + extern grub_uint8_t _edata[]; + + void __attribute__ ((noreturn)) +-grub_exit (void) ++grub_exit (int rc __attribute__((unused))) + { + /* We can't use grub_fatal() in this function. This would create an infinite + loop, since grub_fatal() calls grub_abort() which in turn calls grub_exit(). */ +diff --git a/grub-core/kern/i386/dl.c b/grub-core/kern/i386/dl.c +index 1346da5cc..d6b4681fc 100644 +--- a/grub-core/kern/i386/dl.c ++++ b/grub-core/kern/i386/dl.c +@@ -79,3 +79,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/i386/efi/startup.S b/grub-core/kern/i386/efi/startup.S +index fc5ea3dac..36d1b1a68 100644 +--- a/grub-core/kern/i386/efi/startup.S ++++ b/grub-core/kern/i386/efi/startup.S +@@ -34,3 +34,8 @@ _start: + movl %eax, EXT_C(grub_efi_system_table) + call EXT_C(grub_main) + ret ++ ++/* An executable stack is not required for these functions. */ ++#if defined (__linux__) && defined (__ELF__) ++.section .note.GNU-stack,"",%progbits ++#endif +diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c +index 326d491c5..fe7ad14d4 100644 +--- a/grub-core/kern/i386/pc/init.c ++++ b/grub-core/kern/i386/pc/init.c +@@ -153,7 +153,7 @@ compact_mem_regions (void) + } + + grub_addr_t grub_modbase; +-extern grub_uint8_t _start[], _edata[]; ++extern grub_uint8_t _edata[]; + + /* Helper for grub_machine_init. */ + static int +@@ -226,7 +226,7 @@ grub_machine_init (void) + /* This has to happen before any BIOS calls. */ + grub_via_workaround_init (); + +- grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - _start); ++ grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - (grub_uint8_t *)_start); + + /* Initialize the console as early as possible. */ + grub_console_init (); +diff --git a/grub-core/kern/i386/qemu/init.c b/grub-core/kern/i386/qemu/init.c +index 08f81d25e..604fc94b5 100644 +--- a/grub-core/kern/i386/qemu/init.c ++++ b/grub-core/kern/i386/qemu/init.c +@@ -42,7 +42,7 @@ extern grub_uint8_t _end[]; + extern grub_uint8_t _edata[]; + + void __attribute__ ((noreturn)) +-grub_exit (void) ++grub_exit (int rc __attribute__((unused))) + { + /* We can't use grub_fatal() in this function. This would create an infinite + loop, since grub_fatal() calls grub_abort() which in turn calls grub_exit(). */ +diff --git a/grub-core/kern/i386/qemu/startup.S b/grub-core/kern/i386/qemu/startup.S +index 0d89858d9..939f182fc 100644 +--- a/grub-core/kern/i386/qemu/startup.S ++++ b/grub-core/kern/i386/qemu/startup.S +@@ -24,7 +24,8 @@ + + .text + .code32 +- .globl _start ++ .globl start, _start ++start: + _start: + jmp codestart + +diff --git a/grub-core/kern/ia64/dl.c b/grub-core/kern/ia64/dl.c +index db59300fe..92d82c575 100644 +--- a/grub-core/kern/ia64/dl.c ++++ b/grub-core/kern/ia64/dl.c +@@ -148,3 +148,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + } + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/ia64/efi/startup.S b/grub-core/kern/ia64/efi/startup.S +index d75c6d7cc..8f2a593e5 100644 +--- a/grub-core/kern/ia64/efi/startup.S ++++ b/grub-core/kern/ia64/efi/startup.S +@@ -24,8 +24,9 @@ + .psr lsb + .lsb + +- .global _start ++ .global start, _start + .proc _start ++start: + _start: + alloc loc0=ar.pfs,2,4,0,0 + mov loc1=rp +diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c +index e74de3248..810a089a9 100644 +--- a/grub-core/kern/ieee1275/cmain.c ++++ b/grub-core/kern/ieee1275/cmain.c +@@ -89,7 +89,10 @@ grub_ieee1275_find_options (void) + } + + if (rc >= 0 && grub_strncmp (tmp, "IBM", 3) == 0) +- grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_TREE_SCANNING_FOR_DISKS); ++ { ++ grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_TREE_SCANNING_FOR_DISKS); ++ grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT); ++ } + + /* Old Macs have no key repeat, newer ones have fully working one. + The ones inbetween when repeated key generates an escaoe sequence +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index fb7d1a3ba..6c5f4fb77 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -49,8 +49,9 @@ + #if defined(__powerpc__) || defined(__i386__) + #include + #endif ++#include + +-/* The maximum heap size we're going to claim at boot. Not used by sparc. */ ++/* The maximum heap size we're going to claim. Not used by sparc. */ + #ifdef __i386__ + #define HEAP_MAX_SIZE (unsigned long) (64 * 1024 * 1024) + #else /* __powerpc__ */ +@@ -70,7 +71,6 @@ + */ + #define RUNTIME_MIN_SPACE (128UL * 1024 * 1024) + +-extern char _start[]; + extern char _end[]; + + #ifdef __sparc__ +@@ -113,8 +113,18 @@ grub_addr_t grub_ieee1275_original_stack; + #define DRC_INFO 0x40 + #define BYTE22 (DY_MEM_V2 | DRC_INFO) + ++/* For ibm,arch-vec-5-platform-support. */ ++#define XIVE_INDEX 0x17 ++#define MMU_INDEX 0x18 ++#define RADIX_GTSE_INDEX 0x1a ++#define RADIX_ENABLED 0x40 ++#define XIVE_ENABLED 0x40 ++#define HASH_ENABLED 0x00 ++#define MAX_SUPPORTED 0xC0 ++#define RADIX_GTSE_ENABLED 0x40 ++ + void +-grub_exit (void) ++grub_exit (int rc __attribute__((unused))) + { + grub_ieee1275_exit (); + } +@@ -170,23 +180,25 @@ grub_machine_get_bootlocation (char **device, char **path) + grub_free (canon); + } + else +- *device = grub_ieee1275_encode_devname (bootpath); +- grub_free (type); +- +- filename = grub_ieee1275_get_filename (bootpath); +- if (filename) + { +- char *lastslash = grub_strrchr (filename, '\\'); +- +- /* Truncate at last directory. */ +- if (lastslash) ++ filename = grub_ieee1275_get_filename (bootpath); ++ if (filename) + { +- *lastslash = '\0'; +- grub_translate_ieee1275_path (filename); ++ char *lastslash = grub_strrchr (filename, '\\'); + +- *path = filename; +- } ++ /* Truncate at last directory. */ ++ if (lastslash) ++ { ++ *lastslash = '\0'; ++ grub_translate_ieee1275_path (filename); ++ ++ *path = filename; ++ } ++ } ++ *device = grub_ieee1275_encode_devname (bootpath); + } ++ ++ grub_free (type); + grub_free (bootpath); + } + +@@ -737,6 +749,10 @@ struct option_vector5 + grub_uint32_t platform_facilities; + grub_uint8_t sub_processors; + grub_uint8_t byte22; ++ grub_uint8_t xive; ++ grub_uint8_t mmu; ++ grub_uint8_t hpt_ext; ++ grub_uint8_t radix_gtse; + } GRUB_PACKED; + + struct pvr_entry +@@ -775,6 +791,13 @@ grub_ieee1275_ibm_cas (void) + { + int rc; + grub_ieee1275_ihandle_t root; ++ grub_uint8_t ibm_arch_platform_support[8]; ++ grub_ssize_t actual; ++ grub_uint8_t xive_support = 0; ++ grub_uint8_t mmu_support = 0; ++ grub_uint8_t radix_gtse_support = 0; ++ int i = 0; ++ int prop_len = 8; + struct cas_args + { + struct grub_ieee1275_common_hdr common; +@@ -783,6 +806,46 @@ grub_ieee1275_ibm_cas (void) + grub_ieee1275_cell_t cas_addr; + grub_ieee1275_cell_t result; + } args; ++ ++ grub_ieee1275_get_integer_property (grub_ieee1275_chosen, ++ "ibm,arch-vec-5-platform-support", ++ (grub_uint32_t *) ibm_arch_platform_support, ++ sizeof (ibm_arch_platform_support), ++ &actual); ++ ++ for (i = 0; i < prop_len; i++) ++ { ++ switch (ibm_arch_platform_support[i]) ++ { ++ case XIVE_INDEX: ++ if (ibm_arch_platform_support[i + 1] & MAX_SUPPORTED) ++ xive_support = XIVE_ENABLED; ++ else ++ xive_support = 0; ++ break; ++ ++ case MMU_INDEX: ++ if (ibm_arch_platform_support[i + 1] & MAX_SUPPORTED) ++ mmu_support = RADIX_ENABLED; ++ else ++ mmu_support = HASH_ENABLED; ++ break; ++ ++ case RADIX_GTSE_INDEX: ++ if (mmu_support == RADIX_ENABLED) ++ radix_gtse_support = ibm_arch_platform_support[i + 1] & RADIX_GTSE_ENABLED; ++ else ++ radix_gtse_support = 0; ++ break; ++ ++ default: ++ /* Ignoring the other indexes of ibm,arch-vec-5-platform-support. */ ++ break; ++ } ++ /* Skipping the property value. */ ++ i++; ++ } ++ + struct cas_vector vector = + { + .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */ +@@ -799,7 +862,7 @@ grub_ieee1275_ibm_cas (void) + .vec4 = 0x0001, /* set required minimum capacity % to the lowest value */ + .vec5_size = 1 + sizeof (struct option_vector5) - 2, + .vec5 = { +- 0, BYTE2, 0, CMO, ASSOCIATIVITY, BIN_OPTS, 0, 0, MAX_CPU, 0, 0, PLATFORM_FACILITIES, SUB_PROCESSORS, BYTE22 ++ 0, BYTE2, 0, CMO, ASSOCIATIVITY, BIN_OPTS, 0, 0, MAX_CPU, 0, 0, PLATFORM_FACILITIES, SUB_PROCESSORS, BYTE22, xive_support, mmu_support, 0, radix_gtse_support + } + }; + +@@ -848,6 +911,19 @@ grub_claim_heap (void) + } + #endif + ++#if defined(__powerpc__) ++ if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY)) ++ { ++ grub_uint64_t rma_size; ++ grub_err_t err; ++ ++ err = grub_ieee1275_total_mem (&rma_size); ++ /* if we have an error, don't call CAS, just hope for the best */ ++ if (err == GRUB_ERR_NONE && rma_size < (512 * 1024 * 1024)) ++ grub_ieee1275_ibm_cas (); ++ } ++#endif ++ + grub_machine_mmap_iterate (heap_init, &total); + } + #endif +@@ -892,6 +968,30 @@ grub_parse_cmdline (void) + } + } + ++static void ++grub_get_ieee1275_secure_boot (void) ++{ ++ grub_ieee1275_phandle_t root; ++ int rc; ++ grub_uint32_t is_sb; ++ ++ grub_ieee1275_finddevice ("/", &root); ++ ++ rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", &is_sb, ++ sizeof (is_sb), 0); ++ ++ /* ibm,secure-boot: ++ * 0 - disabled ++ * 1 - audit ++ * 2 - enforce ++ * 3 - enforce + OS-specific behaviour ++ * ++ * We only support enforce. ++ */ ++ if (rc >= 0 && is_sb >= 2) ++ grub_lockdown (); ++} ++ + grub_addr_t grub_modbase; + + void +@@ -917,6 +1017,8 @@ grub_machine_init (void) + #else + grub_install_get_time_ms (grub_rtc_get_time_ms); + #endif ++ ++ grub_get_ieee1275_secure_boot (); + } + + void +diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c +index 11b2beb2f..65616254e 100644 +--- a/grub-core/kern/ieee1275/openfw.c ++++ b/grub-core/kern/ieee1275/openfw.c +@@ -499,7 +499,7 @@ grub_ieee1275_encode_devname (const char *path) + *optr++ ='\\'; + *optr++ = *iptr++; + } +- if (partition && partition[0]) ++ if (partition && partition[0] >= '0' && partition[0] <= '9') + { + unsigned int partno = grub_strtoul (partition, 0, 0); + +@@ -591,3 +591,66 @@ grub_ieee1275_get_boot_dev (void) + + return bootpath; + } ++ ++/* Check if it's a CAS reboot. If so, set the script to be executed. */ ++int ++grub_ieee1275_cas_reboot (char *script) ++{ ++ grub_uint32_t ibm_ca_support_reboot; ++ grub_uint32_t ibm_fw_nbr_reboots; ++ char property_value[10]; ++ grub_ssize_t actual; ++ grub_ieee1275_ihandle_t options; ++ ++ if (grub_ieee1275_finddevice ("/options", &options) < 0) ++ return -1; ++ ++ /* Check two properties, one is enough to get cas reboot value */ ++ ibm_ca_support_reboot = 0; ++ if (grub_ieee1275_get_integer_property (grub_ieee1275_chosen, ++ "ibm,client-architecture-support-reboot", ++ &ibm_ca_support_reboot, ++ sizeof (ibm_ca_support_reboot), ++ &actual) >= 0) ++ grub_dprintf("ieee1275", "ibm,client-architecture-support-reboot: %u\n", ++ ibm_ca_support_reboot); ++ ++ ibm_fw_nbr_reboots = 0; ++ if (grub_ieee1275_get_property (options, "ibm,fw-nbr-reboots", ++ property_value, sizeof (property_value), ++ &actual) >= 0) ++ { ++ property_value[sizeof (property_value) - 1] = 0; ++ ibm_fw_nbr_reboots = (grub_uint8_t) grub_strtoul (property_value, 0, 10); ++ grub_dprintf("ieee1275", "ibm,fw-nbr-reboots: %u\n", ibm_fw_nbr_reboots); ++ } ++ ++ if (ibm_ca_support_reboot || ibm_fw_nbr_reboots) ++ { ++ if (! grub_ieee1275_get_property_length (options, "boot-last-label", &actual)) ++ { ++ if (actual > 1024) ++ script = grub_realloc (script, actual + 1); ++ grub_ieee1275_get_property (options, "boot-last-label", script, actual, ++ &actual); ++ return 0; ++ } ++ } ++ ++ grub_ieee1275_set_boot_last_label (""); ++ ++ return -1; ++} ++ ++int grub_ieee1275_set_boot_last_label (const char *text) ++{ ++ grub_ieee1275_ihandle_t options; ++ grub_ssize_t actual; ++ ++ grub_dprintf("ieee1275", "set boot_last_label (size: %u)\n", grub_strlen(text)); ++ if (! grub_ieee1275_finddevice ("/options", &options) && ++ options != (grub_ieee1275_ihandle_t) -1) ++ grub_ieee1275_set_property (options, "boot-last-label", text, ++ grub_strlen (text), &actual); ++ return 0; ++} +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index 731c07c29..8e89763f4 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -128,16 +128,24 @@ grub_set_prefix_and_root (void) + + grub_machine_get_bootlocation (&fwdevice, &fwpath); + +- if (fwdevice) ++ if (fwdevice && fwpath) + { +- char *cmdpath; ++ char *fw_path; ++ char separator[3] = ")"; + +- cmdpath = grub_xasprintf ("(%s)%s", fwdevice, fwpath ? : ""); +- if (cmdpath) ++ grub_dprintf ("fw_path", "\n"); ++ grub_dprintf ("fw_path", "fwdevice:\"%s\" fwpath:\"%s\"\n", fwdevice, fwpath); ++ ++ if (!grub_strncmp(fwdevice, "http", 4) && fwpath[0] != '/') ++ grub_strcpy(separator, ")/"); ++ ++ fw_path = grub_xasprintf ("(%s%s%s", fwdevice, separator, fwpath); ++ if (fw_path) + { +- grub_env_set ("cmdpath", cmdpath); +- grub_env_export ("cmdpath"); +- grub_free (cmdpath); ++ grub_env_set ("fw_path", fw_path); ++ grub_env_export ("fw_path"); ++ grub_dprintf ("fw_path", "fw_path:\"%s\"\n", fw_path); ++ grub_free (fw_path); + } + } + +@@ -209,12 +217,66 @@ grub_set_prefix_and_root (void) + { + char *prefix_set; + +- prefix_set = grub_xasprintf ("(%s)%s", device, path ? : ""); +- if (prefix_set) ++#ifdef __powerpc__ ++ /* We have to be careful here on powerpc-ieee1275 + signed grub. We ++ will have signed something with a prefix that doesn't have a device ++ because we cannot know in advance what partition we're on. ++ ++ We will have had !device earlier, so we will have set device=fwdevice ++ However, we want to make sure we do not end up setting prefix to be ++ ($fwdevice)/path, because we will then end up trying to boot or search ++ based on a prefix of (ieee1275/disk)/path, which will not work because ++ it's missing a partition. ++ ++ Also: ++ - You can end up with a device with an FS directly on it, without ++ a partition, e.g. ieee1275/cdrom. ++ ++ - powerpc-ieee1275 + grub-install sets e.g. prefix=(,gpt2)/path, ++ which will have now been extended to device=$fwdisk,partition ++ and path=/path ++ ++ - PowerVM will give us device names like ++ ieee1275//vdevice/v-scsi@3000006c/disk@8100000000000000 ++ and we don't want to try to encode some sort of truth table about ++ what sorts of paths represent disks with partition tables and those ++ without partition tables. ++ ++ - Frustratingly, the device name itself can contain an embedded comma: ++ /pci@800000020000015/pci1014,034A@0/sas/disk@5000c50098a0ee8b ++ So we cannot even rely upon the presence of a comma to say that a ++ partition has been specified! ++ ++ If we only have a path in $prefix, the code in normal to discover ++ config files will try all disks, both without partitions and then with ++ any partitions so we will cover both CDs and HDs. ++ ++ However, it doesn't then set the prefix to be something like ++ (discovered partition)/path, and so it is fragile against runtime ++ changes to $root. For example some of the stuff done in 10_linux to ++ reload $root sets root differently and then uses search to find it ++ again. If the search module is not built in, when we change root, grub ++ will look in (new root)/path/powerpc-ieee1275, that won't work, and we ++ will not be able to load the search module and the boot will fail. ++ ++ This is particularly likely to hit us in the grub-install ++ (,msdos2)/grub2 case, so we act unless the supplied prefix starts with ++ '(', which would likely indicate a partition has already been ++ specified. ++ */ ++ if (prefix && prefix[0] != '(') ++ grub_env_set ("prefix", path); ++ else ++#endif + { +- grub_env_set ("prefix", prefix_set); +- grub_free (prefix_set); ++ prefix_set = grub_xasprintf ("(%s)%s", device, path ? : ""); ++ if (prefix_set) ++ { ++ grub_env_set ("prefix", prefix_set); ++ grub_free (prefix_set); ++ } + } ++ + grub_env_set ("root", device); + } + +diff --git a/grub-core/kern/mips/arc/init.c b/grub-core/kern/mips/arc/init.c +index 2ed3ff319..5c40c3407 100644 +--- a/grub-core/kern/mips/arc/init.c ++++ b/grub-core/kern/mips/arc/init.c +@@ -276,7 +276,7 @@ grub_halt (void) + } + + void +-grub_exit (void) ++grub_exit (int rc __attribute__((unused))) + { + GRUB_ARC_FIRMWARE_VECTOR->exit (); + +diff --git a/grub-core/kern/mips/dl.c b/grub-core/kern/mips/dl.c +index 5b02f97fc..db411899d 100644 +--- a/grub-core/kern/mips/dl.c ++++ b/grub-core/kern/mips/dl.c +@@ -272,3 +272,11 @@ grub_arch_dl_init_linker (void) + grub_dl_register_symbol ("_gp_disp", &_gp_disp_dummy, 0, 0); + } + ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/mips/loongson/init.c b/grub-core/kern/mips/loongson/init.c +index 5bd721260..97b09b0ee 100644 +--- a/grub-core/kern/mips/loongson/init.c ++++ b/grub-core/kern/mips/loongson/init.c +@@ -304,7 +304,7 @@ grub_halt (void) + } + + void +-grub_exit (void) ++grub_exit (int rc __attribute__((unused))) + { + grub_halt (); + } +diff --git a/grub-core/kern/mips/qemu_mips/init.c b/grub-core/kern/mips/qemu_mips/init.c +index b5477b87f..69488a34e 100644 +--- a/grub-core/kern/mips/qemu_mips/init.c ++++ b/grub-core/kern/mips/qemu_mips/init.c +@@ -75,7 +75,7 @@ grub_machine_fini (int flags __attribute__ ((unused))) + } + + void +-grub_exit (void) ++grub_exit (int rc __attribute__((unused))) + { + grub_halt (); + } +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index 7cee5d75c..98700423d 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -26,6 +26,10 @@ + #include + #include + #include ++#include ++#if DEBUG_WITH_TIMESTAMPS ++#include ++#endif + + union printf_arg + { +@@ -182,6 +186,19 @@ int grub_err_printf (const char *fmt, ...) + __attribute__ ((alias("grub_printf"))); + #endif + ++/* Return 1 if 'debug' is set and not empty */ ++int ++grub_debug_is_enabled (void) ++{ ++ const char *debug; ++ ++ debug = grub_env_get ("debug"); ++ if (!debug || debug[0] == '\0') ++ return 0; ++ ++ return 1; ++} ++ + int + grub_debug_enabled (const char * condition) + { +@@ -235,9 +252,26 @@ grub_real_dprintf (const char *file, const int line, const char *condition, + const char *fmt, ...) + { + va_list args; ++#if DEBUG_WITH_TIMESTAMPS ++ static long unsigned int last_time = 0; ++ static int last_had_cr = 1; ++#endif + + if (grub_debug_enabled (condition)) + { ++#if DEBUG_WITH_TIMESTAMPS ++ /* Don't print timestamp if last printed message isn't terminated yet */ ++ if (last_had_cr) { ++ long unsigned int tmabs = (long unsigned int) grub_get_time_ms(); ++ long unsigned int tmrel = tmabs - last_time; ++ last_time = tmabs; ++ grub_printf ("%3lu.%03lus +%2lu.%03lus ", tmabs / 1000, tmabs % 1000, tmrel / 1000, tmrel % 1000); ++ } ++ if (fmt[grub_strlen(fmt)-1] == '\n') ++ last_had_cr = 1; ++ else ++ last_had_cr = 0; ++#endif + grub_printf ("%s:%d:%s: ", file, line, condition); + va_start (args, fmt); + grub_vprintf (fmt, args); +@@ -246,6 +280,24 @@ grub_real_dprintf (const char *file, const int line, const char *condition, + } + } + ++void ++grub_qdprintf (const char *condition, const char *fmt, ...) ++{ ++ va_list args; ++ const char *debug = grub_env_get ("debug"); ++ ++ if (! debug) ++ return; ++ ++ if (grub_strword (debug, "all") || grub_strword (debug, condition)) ++ { ++ va_start (args, fmt); ++ grub_vprintf (fmt, args); ++ va_end (args); ++ grub_refresh (); ++ } ++} ++ + #define PREALLOC_SIZE 255 + + int +@@ -611,6 +663,36 @@ grub_reverse (char *str) + } + } + ++/* Separate string into two parts, broken up by delimiter delim. */ ++void ++grub_str_sep (const char *s, char *p, char delim, char *r) ++{ ++ char* t = grub_strndup(s, grub_strlen(s)); ++ ++ if (t != NULL && *t != '\0') ++ { ++ char* tmp = t; ++ ++ while (((*p = *t) != '\0') && ((*p = *t) != delim)) ++ { ++ p++; ++ t++; ++ } ++ *p = '\0'; ++ ++ if (*t != '\0') ++ { ++ t++; ++ while ((*r++ = *t++) != '\0') ++ ; ++ *r = '\0'; ++ } ++ grub_free (tmp); ++ } ++ else ++ grub_free (t); ++} ++ + /* Divide N by D, return the quotient, and store the remainder in *R. */ + grub_uint64_t + grub_divmod64 (grub_uint64_t n, grub_uint64_t d, grub_uint64_t *r) +@@ -1301,7 +1383,12 @@ grub_printf_fmt_check (const char *fmt, const char *fmt_expected) + void __attribute__ ((noreturn)) + grub_abort (void) + { +- grub_printf ("\nAborted."); ++#if !defined(GRUB_MACHINE_EMU) && !defined(GRUB_UTIL) ++ grub_backtrace (1); ++#else ++ grub_printf ("\n"); ++#endif ++ grub_printf ("Aborted."); + + #ifndef GRUB_UTIL + if (grub_term_inputs) +@@ -1311,14 +1398,24 @@ grub_abort (void) + grub_getkey (); + } + +- grub_exit (); ++ grub_exit (1); + } + ++#if defined (__clang__) && !defined (GRUB_UTIL) ++/* clang emits references to abort(). */ ++void __attribute__ ((noreturn)) ++abort (void) ++{ ++ grub_abort (); ++} ++#endif ++ + void + grub_fatal (const char *fmt, ...) + { + va_list ap; + ++ grub_printf ("\n"); + va_start (ap, fmt); + grub_vprintf (_(fmt), ap); + va_end (ap); +@@ -1389,6 +1486,7 @@ grub_real_boot_time (const char *file, + + va_start (args, fmt); + n->msg = grub_xvasprintf (fmt, args); ++ grub_dprintf ("boot", "%s\n", n->msg); + va_end (args); + + *boot_time_last = n; +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index 027a25cd1..819bc5126 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -144,13 +144,13 @@ get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r) + break; + + if (! *r) +- grub_fatal ("out of range pointer %p", ptr); ++ grub_fatal ("out of range pointer %p\n", ptr); + + *p = (grub_mm_header_t) ptr - 1; + if ((*p)->magic == GRUB_MM_FREE_MAGIC) +- grub_fatal ("double free at %p", *p); ++ grub_fatal ("double free at %p\n", *p); + if ((*p)->magic != GRUB_MM_ALLOC_MAGIC) +- grub_fatal ("alloc magic is broken at %p: %lx", *p, ++ grub_fatal ("alloc magic is broken at %p: %lx\n", *p, + (unsigned long) (*p)->magic); + } + +@@ -505,7 +505,7 @@ grub_memalign (grub_size_t align, grub_size_t size) + goto fail; + + /* Preallocate some extra space if heap growth is small. */ +- grow = grub_max (grow, GRUB_MM_HEAP_GROW_EXTRA); ++ grow = grub_max (grow, (grub_size_t)GRUB_MM_HEAP_GROW_EXTRA); + + /* Align up heap growth to make it friendly to CPU/MMU. */ + if (grow > ~(grub_size_t) (GRUB_MM_HEAP_GROW_ALIGN - 1)) +diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c +index 7b6418eab..0eb8bc5bd 100644 +--- a/grub-core/kern/powerpc/dl.c ++++ b/grub-core/kern/powerpc/dl.c +@@ -167,3 +167,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/riscv/dl.c b/grub-core/kern/riscv/dl.c +index 896653bb4..1fa085b4a 100644 +--- a/grub-core/kern/riscv/dl.c ++++ b/grub-core/kern/riscv/dl.c +@@ -344,3 +344,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/riscv/efi/startup.S b/grub-core/kern/riscv/efi/startup.S +index f2a7b2b1e..781773136 100644 +--- a/grub-core/kern/riscv/efi/startup.S ++++ b/grub-core/kern/riscv/efi/startup.S +@@ -29,6 +29,7 @@ + + .file "startup.S" + .text ++FUNCTION(start) + FUNCTION(_start) + /* + * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in a1/a0. +diff --git a/grub-core/kern/sparc64/dl.c b/grub-core/kern/sparc64/dl.c +index f3d960186..f054f0824 100644 +--- a/grub-core/kern/sparc64/dl.c ++++ b/grub-core/kern/sparc64/dl.c +@@ -189,3 +189,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/sparc64/ieee1275/crt0.S b/grub-core/kern/sparc64/ieee1275/crt0.S +index 03b916f05..701bf63ab 100644 +--- a/grub-core/kern/sparc64/ieee1275/crt0.S ++++ b/grub-core/kern/sparc64/ieee1275/crt0.S +@@ -22,7 +22,8 @@ + + .text + .align 4 +- .globl _start ++ .globl start, _start ++start: + _start: + ba codestart + mov %o4, %o0 +diff --git a/grub-core/kern/term.c b/grub-core/kern/term.c +index 14d596498..4d61f4e97 100644 +--- a/grub-core/kern/term.c ++++ b/grub-core/kern/term.c +@@ -144,9 +144,10 @@ grub_key_is_interrupt (int key) + /* + * ESC sometimes is the BIOS setup hotkey and may be hard to discover, also + * check F4, which was chosen because is not used as a hotkey to enter the +- * BIOS setup by any vendor. ++ * BIOS setup by any vendor. Also, F8 which was the key to get the Windows ++ * bootmenu for a long time. + */ +- if (key == GRUB_TERM_ESC || key == GRUB_TERM_KEY_F4) ++ if (key == GRUB_TERM_ESC || key == GRUB_TERM_KEY_F4 || key == GRUB_TERM_KEY_F8) + return 1; + + /* +diff --git a/grub-core/kern/uboot/init.c b/grub-core/kern/uboot/init.c +index 3e338645c..be2a5be1d 100644 +--- a/grub-core/kern/uboot/init.c ++++ b/grub-core/kern/uboot/init.c +@@ -39,9 +39,9 @@ extern grub_size_t grub_total_module_size; + static unsigned long timer_start; + + void +-grub_exit (void) ++grub_exit (int rc) + { +- grub_uboot_return (0); ++ grub_uboot_return (rc < 0 ? 1 : rc); + } + + static grub_uint64_t +@@ -78,7 +78,7 @@ grub_machine_init (void) + if (!ver) + { + /* Don't even have a console to log errors to... */ +- grub_exit (); ++ grub_exit (-1); + } + else if (ver > API_SIG_VERSION) + { +diff --git a/grub-core/kern/x86_64/dl.c b/grub-core/kern/x86_64/dl.c +index e5a8bdcf4..a105dc50c 100644 +--- a/grub-core/kern/x86_64/dl.c ++++ b/grub-core/kern/x86_64/dl.c +@@ -119,3 +119,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/x86_64/efi/startup.S b/grub-core/kern/x86_64/efi/startup.S +index 9357e5c5d..f5c6bc3d8 100644 +--- a/grub-core/kern/x86_64/efi/startup.S ++++ b/grub-core/kern/x86_64/efi/startup.S +@@ -33,3 +33,8 @@ _start: + andq $~0xf, %rsp + call EXT_C(grub_main) + /* Doesn't return. */ ++ ++/* An executable stack is not required for these functions. */ ++#if defined (__linux__) && defined (__ELF__) ++.section .note.GNU-stack,"",%progbits ++#endif +diff --git a/grub-core/kern/xen/init.c b/grub-core/kern/xen/init.c +index 782ca7295..708b060f3 100644 +--- a/grub-core/kern/xen/init.c ++++ b/grub-core/kern/xen/init.c +@@ -584,7 +584,7 @@ grub_machine_init (void) + } + + void +-grub_exit (void) ++grub_exit (int rc __attribute__((unused))) + { + struct sched_shutdown arg; + +diff --git a/grub-core/lib/.gitignore b/grub-core/lib/.gitignore +new file mode 100644 +index 000000000..681545914 +--- /dev/null ++++ b/grub-core/lib/.gitignore +@@ -0,0 +1 @@ ++/libgcrypt-grub/ +diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c +index ed0b149dc..8e2294d8f 100644 +--- a/grub-core/lib/cmdline.c ++++ b/grub-core/lib/cmdline.c +@@ -20,6 +20,12 @@ + #include + #include + ++static int ++is_hex(char c) ++{ ++ return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); ++} ++ + static unsigned int check_arg (char *c, int *has_space) + { + int space = 0; +@@ -27,7 +33,13 @@ static unsigned int check_arg (char *c, int *has_space) + + while (*c) + { +- if (*c == '\\' || *c == '\'' || *c == '"') ++ if (*c == '\\' && *(c+1) == 'x' && is_hex(*(c+2)) && is_hex(*(c+3))) ++ { ++ size += 4; ++ c += 4; ++ continue; ++ } ++ else if (*c == '\\' || *c == '\'' || *c == '"') + size++; + else if (*c == ' ') + space = 1; +@@ -86,7 +98,16 @@ grub_create_loader_cmdline (int argc, char *argv[], char *buf, + + while (*c) + { +- if (*c == '\\' || *c == '\'' || *c == '"') ++ if (*c == '\\' && *(c+1) == 'x' && ++ is_hex(*(c+2)) && is_hex(*(c+3))) ++ { ++ *buf++ = *c++; ++ *buf++ = *c++; ++ *buf++ = *c++; ++ *buf++ = *c++; ++ continue; ++ } ++ else if (*c == '\\' || *c == '\'' || *c == '"') + *buf++ = '\\'; + + *buf++ = *c; +diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c +index 396f76410..d53ddbe2c 100644 +--- a/grub-core/lib/crypto.c ++++ b/grub-core/lib/crypto.c +@@ -121,6 +121,10 @@ grub_md_unregister (gcry_md_spec_t *cipher) + } + } + ++struct gcry_pk_spec *grub_crypto_pk_dsa; ++struct gcry_pk_spec *grub_crypto_pk_ecdsa; ++struct gcry_pk_spec *grub_crypto_pk_rsa; ++ + void + grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in, + grub_size_t inlen) +diff --git a/grub-core/lib/envblk.c b/grub-core/lib/envblk.c +index 2e4e78b13..874506da1 100644 +--- a/grub-core/lib/envblk.c ++++ b/grub-core/lib/envblk.c +@@ -223,6 +223,49 @@ grub_envblk_delete (grub_envblk_t envblk, const char *name) + } + } + ++struct get_var_state { ++ const char * const name; ++ char * value; ++ int found; ++}; ++ ++static int ++get_var (const char * const name, const char * const value, void *statep) ++{ ++ struct get_var_state *state = (struct get_var_state *)statep; ++ ++ if (!grub_strcmp(state->name, name)) ++ { ++ state->found = 1; ++ state->value = grub_strdup(value); ++ if (!state->value) ++ grub_errno = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ ++ return 1; ++ } ++ ++ return 0; ++} ++ ++grub_err_t ++grub_envblk_get (grub_envblk_t envblk, const char * const name, char ** const value) ++{ ++ struct get_var_state state = { ++ .name = name, ++ .value = NULL, ++ .found = 0, ++ }; ++ ++ grub_envblk_iterate(envblk, (void *)&state, get_var); ++ ++ *value = state.value; ++ ++ if (state.found && !state.value) ++ return grub_errno; ++ ++ return GRUB_ERR_NONE; ++} ++ + void + grub_envblk_iterate (grub_envblk_t envblk, + void *hook_data, +diff --git a/grub-core/lib/fdt.c b/grub-core/lib/fdt.c +index 73cfa94a2..fbf749e1d 100644 +--- a/grub-core/lib/fdt.c ++++ b/grub-core/lib/fdt.c +@@ -21,8 +21,6 @@ + #include + #include + +-GRUB_MOD_LICENSE ("GPLv3+"); +- + #define FDT_SUPPORTED_VERSION 17 + + #define FDT_BEGIN_NODE 0x00000001 +diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c +deleted file mode 100644 +index c3e03c727..000000000 +--- a/grub-core/lib/i386/backtrace.c ++++ /dev/null +@@ -1,66 +0,0 @@ +-/* +- * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2009 Free Software Foundation, Inc. +- * +- * GRUB is free software: you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation, either version 3 of the License, or +- * (at your option) any later version. +- * +- * GRUB 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 General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with GRUB. If not, see . +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define MAX_STACK_FRAME 102400 +- +-void +-grub_backtrace_pointer (void *ebp) +-{ +- void *ptr, *nptr; +- unsigned i; +- +- ptr = ebp; +- while (1) +- { +- grub_printf ("%p: ", ptr); +- grub_backtrace_print_address (((void **) ptr)[1]); +- grub_printf (" ("); +- for (i = 0; i < 2; i++) +- grub_printf ("%p,", ((void **)ptr) [i + 2]); +- grub_printf ("%p)\n", ((void **)ptr) [i + 2]); +- nptr = *(void **)ptr; +- if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME +- || nptr == ptr) +- { +- grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr); +- break; +- } +- ptr = nptr; +- } +-} +- +-void +-grub_backtrace (void) +-{ +-#ifdef __x86_64__ +- asm volatile ("movq %%rbp, %%rdi\n" +- "callq *%%rax": :"a"(grub_backtrace_pointer)); +-#else +- asm volatile ("movl %%ebp, %%eax\n" +- "calll *%%ecx": :"c"(grub_backtrace_pointer)); +-#endif +-} +- +diff --git a/grub-core/lib/libtasn1/LICENSE b/grub-core/lib/libtasn1/LICENSE +new file mode 100644 +index 000000000..e8b3628db +--- /dev/null ++++ b/grub-core/lib/libtasn1/LICENSE +@@ -0,0 +1,16 @@ ++LICENSING ++========= ++ ++The libtasn1 library is released under the GNU Lesser General Public ++License (LGPL) version 2.1 or later; see [COPYING.LESSER](doc/COPYING.LESSER) ++for the license terms. ++ ++The GNU LGPL applies to the main libtasn1 library, while the ++included applications library are under the GNU GPL version 3. ++The libtasn1 library is located in the lib directory, while the applications ++in src/. ++ ++The documentation in doc/ is under the GNU FDL license 1.3. ++ ++For any copyright year range specified as YYYY-ZZZZ in this package ++note that the range specifies every single year in that closed interval. +diff --git a/grub-core/lib/libtasn1/README.md b/grub-core/lib/libtasn1/README.md +new file mode 100644 +index 000000000..50a864229 +--- /dev/null ++++ b/grub-core/lib/libtasn1/README.md +@@ -0,0 +1,91 @@ ++|Branch|CI system|Status| ++|:----:|:-------:|-----:| ++|Master|Gitlab|[![build status](https://gitlab.com/gnutls/libtasn1/badges/master/pipeline.svg)](https://gitlab.com/gnutls/libtasn1/commits/master)[![coverage report](https://gitlab.com/gnutls/libtasn1/badges/master/coverage.svg)](https://gnutls.gitlab.io/libtasn1/coverage)| ++ ++# libtasn1 ++ ++This is GNU Libtasn1, a small ASN.1 library. ++ ++The C library (libtasn1.*) is licensed under the GNU Lesser General ++Public License version 2.1 or later. See the file COPYING.LIB. ++ ++The command line tool, self tests, examples, and other auxilliary ++files, are licensed under the GNU General Public License version 3.0 ++or later. See the file COPYING. ++ ++## Building the library ++ ++We require several tools to build the software, including: ++ ++* [Make](https://www.gnu.org/software/make/) ++* [Automake](https://www.gnu.org/software/automake/) (use 1.11.3 or later) ++* [Autoconf](https://www.gnu.org/software/autoconf/) ++* [Libtool](https://www.gnu.org/software/libtool/) ++* [Texinfo](https://www.gnu.org/software/texinfo/) ++* [help2man](http://www.gnu.org/software/help2man/) ++* [Tar](https://www.gnu.org/software/tar/) ++* [Gzip](https://www.gnu.org/software/gzip/) ++* [bison](https://www.gnu.org/software/bison/) ++* [Texlive & epsf](https://www.tug.org/texlive/) (for PDF manual) ++* [GTK-DOC](https://www.gtk.org/gtk-doc/) (for API manual) ++* [Git](https://git-scm.com/) ++* [libabigail](https://pagure.io/libabigail/) (for abi comparison in make dist) ++* [Valgrind](https://valgrind.org/) (optional) ++ ++The required software is typically distributed with your operating ++system, and the instructions for installing them differ. Here are ++some hints: ++ ++gNewSense/Debian/Ubuntu: ++``` ++sudo apt-get install make git-core autoconf automake libtool ++sudo apt-get install texinfo texlive texlive-generic-recommended texlive-extra-utils ++sudo apt-get install help2man gtk-doc-tools valgrind abigail-tools ++``` ++ ++The next step is to run autoreconf, ./configure, etc: ++ ++``` ++$ ./bootstrap ++``` ++ ++Then build the project normally: ++ ++``` ++$ make ++$ make check ++``` ++ ++Happy hacking! ++ ++ ++## Manual ++ ++The manual is in the `doc/` directory of the release. You can also browse ++the manual online at: ++ ++ - https://gnutls.gitlab.io/libtasn1/ ++ ++ ++## Code coverage report ++ ++The coverage report is at: ++ ++ - https://gnutls.gitlab.io/libtasn1/coverage ++ ++ ++## Issue trackers ++ ++ - [Main issue tracker](https://gitlab.com/gnutls/libtasn1/issues) ++ - [oss-fuzz found issues](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=libtasn1&can=2) ++ ++ ++## Homepage ++ ++The project homepage at the gnu site is at: ++ ++http://www.gnu.org/software/libtasn1/ ++ ++ ++For any copyright year range specified as YYYY-ZZZZ in this package ++note that the range specifies every single year in that closed interval. +diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c +new file mode 100644 +index 000000000..52def5983 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/coding.c +@@ -0,0 +1,1423 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++ ++/*****************************************************/ ++/* File: coding.c */ ++/* Description: Functions to create a DER coding of */ ++/* an ASN1 type. */ ++/*****************************************************/ ++ ++#include ++#include "parser_aux.h" ++#include ++#include "element.h" ++#include ++ ++#define MAX_TAG_LEN 16 ++ ++#if 0 ++/******************************************************/ ++/* Function : _asn1_error_description_value_not_found */ ++/* Description: creates the ErrorDescription string */ ++/* for the ASN1_VALUE_NOT_FOUND error. */ ++/* Parameters: */ ++/* node: node of the tree where the value is NULL. */ ++/* ErrorDescription: string returned. */ ++/* Return: */ ++/******************************************************/ ++static void ++_asn1_error_description_value_not_found (asn1_node node, ++ char *ErrorDescription) ++{ ++ ++ if (ErrorDescription == NULL) ++ return; ++ ++ Estrcpy (ErrorDescription, ":: value of element '"); ++ _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription), ++ ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40); ++ Estrcat (ErrorDescription, "' not found"); ++ ++} ++#endif ++ ++/** ++ * asn1_length_der: ++ * @len: value to convert. ++ * @der: buffer to hold the returned encoding (may be %NULL). ++ * @der_len: number of meaningful bytes of ANS (der[0]..der[der_len-1]). ++ * ++ * Creates the DER encoding of the provided length value. ++ * The @der buffer must have enough room for the output. The maximum ++ * length this function will encode is %ASN1_MAX_LENGTH_SIZE. ++ * ++ * To know the size of the DER encoding use a %NULL value for @der. ++ **/ ++void ++asn1_length_der (unsigned long int len, unsigned char *der, int *der_len) ++{ ++ int k; ++ unsigned char temp[ASN1_MAX_LENGTH_SIZE]; ++#if SIZEOF_UNSIGNED_LONG_INT > 8 ++ len &= 0xFFFFFFFFFFFFFFFF; ++#endif ++ ++ if (len < 128) ++ { ++ /* short form */ ++ if (der != NULL) ++ der[0] = (unsigned char) len; ++ *der_len = 1; ++ } ++ else ++ { ++ /* Long form */ ++ k = 0; ++ while (len) ++ { ++ temp[k++] = len & 0xFF; ++ len = len >> 8; ++ } ++ *der_len = k + 1; ++ if (der != NULL) ++ { ++ der[0] = ((unsigned char) k & 0x7F) + 128; ++ while (k--) ++ der[*der_len - 1 - k] = temp[k]; ++ } ++ } ++} ++ ++/******************************************************/ ++/* Function : _asn1_tag_der */ ++/* Description: creates the DER coding for the CLASS */ ++/* and TAG parameters. */ ++/* It is limited by the ASN1_MAX_TAG_SIZE variable */ ++/* Parameters: */ ++/* class: value to convert. */ ++/* tag_value: value to convert. */ ++/* ans: string returned. */ ++/* ans_len: number of meaningful bytes of ANS */ ++/* (ans[0]..ans[ans_len-1]). */ ++/* Return: */ ++/******************************************************/ ++static void ++_asn1_tag_der (unsigned char class, unsigned int tag_value, ++ unsigned char ans[ASN1_MAX_TAG_SIZE], int *ans_len) ++{ ++ int k; ++ unsigned char temp[ASN1_MAX_TAG_SIZE]; ++ ++ if (tag_value < 31) ++ { ++ /* short form */ ++ ans[0] = (class & 0xE0) + ((unsigned char) (tag_value & 0x1F)); ++ *ans_len = 1; ++ } ++ else ++ { ++ /* Long form */ ++ ans[0] = (class & 0xE0) + 31; ++ k = 0; ++ while (tag_value != 0) ++ { ++ temp[k++] = tag_value & 0x7F; ++ tag_value >>= 7; ++ ++ if (k > ASN1_MAX_TAG_SIZE - 1) ++ break; /* will not encode larger tags */ ++ } ++ *ans_len = k + 1; ++ while (k--) ++ ans[*ans_len - 1 - k] = temp[k] + 128; ++ ans[*ans_len - 1] -= 128; ++ } ++} ++ ++/** ++ * asn1_octet_der: ++ * @str: the input data. ++ * @str_len: STR length (str[0]..str[*str_len-1]). ++ * @der: encoded string returned. ++ * @der_len: number of meaningful bytes of DER (der[0]..der[der_len-1]). ++ * ++ * Creates a length-value DER encoding for the input data. ++ * The DER encoding of the input data will be placed in the @der variable. ++ * ++ * Note that the OCTET STRING tag is not included in the output. ++ * ++ * This function does not return any value because it is expected ++ * that @der_len will contain enough bytes to store the string ++ * plus the DER encoding. The DER encoding size can be obtained using ++ * asn1_length_der(). ++ **/ ++void ++asn1_octet_der (const unsigned char *str, int str_len, ++ unsigned char *der, int *der_len) ++{ ++ int len_len; ++ ++ if (der == NULL || str_len < 0) ++ return; ++ ++ asn1_length_der (str_len, der, &len_len); ++ memcpy (der + len_len, str, str_len); ++ *der_len = str_len + len_len; ++} ++ ++ ++/** ++ * asn1_encode_simple_der: ++ * @etype: The type of the string to be encoded (ASN1_ETYPE_) ++ * @str: the string data. ++ * @str_len: the string length ++ * @tl: the encoded tag and length ++ * @tl_len: the bytes of the @tl field ++ * ++ * Creates the DER encoding for various simple ASN.1 types like strings etc. ++ * It stores the tag and length in @tl, which should have space for at least ++ * %ASN1_MAX_TL_SIZE bytes. Initially @tl_len should contain the size of @tl. ++ * ++ * The complete DER encoding should consist of the value in @tl appended ++ * with the provided @str. ++ * ++ * Returns: %ASN1_SUCCESS if successful or an error value. ++ **/ ++int ++asn1_encode_simple_der (unsigned int etype, const unsigned char *str, ++ unsigned int str_len, unsigned char *tl, ++ unsigned int *tl_len) ++{ ++ int tag_len, len_len; ++ unsigned tlen; ++ unsigned char der_tag[ASN1_MAX_TAG_SIZE]; ++ unsigned char der_length[ASN1_MAX_LENGTH_SIZE]; ++ unsigned char *p; ++ ++ if (str == NULL) ++ return ASN1_VALUE_NOT_VALID; ++ ++ if (ETYPE_OK (etype) == 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ /* doesn't handle constructed classes */ ++ if (ETYPE_CLASS (etype) != ASN1_CLASS_UNIVERSAL) ++ return ASN1_VALUE_NOT_VALID; ++ ++ _asn1_tag_der (ETYPE_CLASS (etype), ETYPE_TAG (etype), der_tag, &tag_len); ++ ++ asn1_length_der (str_len, der_length, &len_len); ++ ++ if (tag_len <= 0 || len_len <= 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ tlen = tag_len + len_len; ++ ++ if (*tl_len < tlen) ++ return ASN1_MEM_ERROR; ++ ++ p = tl; ++ memcpy (p, der_tag, tag_len); ++ p += tag_len; ++ memcpy (p, der_length, len_len); ++ ++ *tl_len = tlen; ++ ++ return ASN1_SUCCESS; ++} ++ ++#if 0 ++/******************************************************/ ++/* Function : _asn1_time_der */ ++/* Description: creates the DER coding for a TIME */ ++/* type (length included). */ ++/* Parameters: */ ++/* str: TIME null-terminated string. */ ++/* der: string returned. */ ++/* der_len: number of meaningful bytes of DER */ ++/* (der[0]..der[ans_len-1]). Initially it */ ++/* if must store the lenght of DER. */ ++/* Return: */ ++/* ASN1_MEM_ERROR when DER isn't big enough */ ++/* ASN1_SUCCESS otherwise */ ++/******************************************************/ ++static int ++_asn1_time_der (unsigned char *str, int str_len, unsigned char *der, ++ int *der_len) ++{ ++ int len_len; ++ int max_len; ++ ++ if (der == NULL) ++ return ASN1_VALUE_NOT_VALID; ++ ++ max_len = *der_len; ++ ++ asn1_length_der (str_len, (max_len > 0) ? der : NULL, &len_len); ++ ++ if ((len_len + str_len) <= max_len) ++ memcpy (der + len_len, str, str_len); ++ *der_len = len_len + str_len; ++ ++ if ((*der_len) > max_len) ++ return ASN1_MEM_ERROR; ++ ++ return ASN1_SUCCESS; ++} ++#endif ++ ++/* ++void ++_asn1_get_utctime_der(unsigned char *der,int *der_len,unsigned char *str) ++{ ++ int len_len,str_len; ++ char temp[20]; ++ ++ if(str==NULL) return; ++ str_len=asn1_get_length_der(der,*der_len,&len_len); ++ if (str_len<0) return; ++ memcpy(temp,der+len_len,str_len); ++ *der_len=str_len+len_len; ++ switch(str_len) ++ { ++ case 11: ++ temp[10]=0; ++ strcat(temp,"00+0000"); ++ break; ++ case 13: ++ temp[12]=0; ++ strcat(temp,"+0000"); ++ break; ++ case 15: ++ temp[15]=0; ++ memmove(temp+12,temp+10,6); ++ temp[10]=temp[11]='0'; ++ break; ++ case 17: ++ temp[17]=0; ++ break; ++ default: ++ return; ++ } ++ strcpy(str,temp); ++} ++*/ ++ ++static ++void encode_val(uint64_t val, unsigned char *der, int max_len, int *der_len) ++{ ++ int first, k; ++ unsigned char bit7; ++ ++ first = 0; ++ for (k = sizeof(val); k >= 0; k--) ++ { ++ bit7 = (val >> (k * 7)) & 0x7F; ++ if (bit7 || first || !k) ++ { ++ if (k) ++ bit7 |= 0x80; ++ if (max_len > (*der_len)) ++ der[*der_len] = bit7; ++ (*der_len)++; ++ first = 1; ++ } ++ } ++} ++ ++/******************************************************/ ++/* Function : _asn1_object_id_der */ ++/* Description: creates the DER coding for an */ ++/* OBJECT IDENTIFIER type (length included). */ ++/* Parameters: */ ++/* str: OBJECT IDENTIFIER null-terminated string. */ ++/* der: string returned. */ ++/* der_len: number of meaningful bytes of DER */ ++/* (der[0]..der[ans_len-1]). Initially it */ ++/* must store the length of DER. */ ++/* Return: */ ++/* ASN1_MEM_ERROR when DER isn't big enough */ ++/* ASN1_SUCCESS if succesful */ ++/* or an error value. */ ++/******************************************************/ ++static int ++_asn1_object_id_der (const char *str, unsigned char *der, int *der_len) ++{ ++ int len_len, counter, max_len; ++ char *temp, *n_end, *n_start; ++ uint64_t val, val1 = 0; ++ int str_len = _asn1_strlen (str); ++ ++ max_len = *der_len; ++ *der_len = 0; ++ ++ if (der == NULL && max_len > 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ temp = malloc (str_len + 2); ++ if (temp == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ ++ memcpy (temp, str, str_len); ++ temp[str_len] = '.'; ++ temp[str_len + 1] = 0; ++ ++ counter = 0; ++ n_start = temp; ++ while ((n_end = strchr (n_start, '.'))) ++ { ++ *n_end = 0; ++ val = _asn1_strtou64 (n_start, NULL, 10); ++ counter++; ++ ++ if (counter == 1) ++ { ++ val1 = val; ++ } ++ else if (counter == 2) ++ { ++ uint64_t val0; ++ ++ if (val1 > 2) ++ { ++ free(temp); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ else if ((val1 == 0 || val1 == 1) && val > 39) ++ { ++ free(temp); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ val0 = 40 * val1 + val; ++ encode_val(val0, der, max_len, der_len); ++ } ++ else ++ { ++ encode_val(val, der, max_len, der_len); ++ } ++ n_start = n_end + 1; ++ } ++ ++ asn1_length_der (*der_len, NULL, &len_len); ++ if (max_len >= (*der_len + len_len)) ++ { ++ memmove (der + len_len, der, *der_len); ++ asn1_length_der (*der_len, der, &len_len); ++ } ++ *der_len += len_len; ++ ++ free (temp); ++ ++ if (max_len < (*der_len)) ++ return ASN1_MEM_ERROR; ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_object_id_der: ++ * @str: An object identifier in numeric, dot format. ++ * @der: buffer to hold the returned encoding (may be %NULL). ++ * @der_len: initially the size of @der; will hold the final size. ++ * @flags: must be zero ++ * ++ * Creates the DER encoding of the provided object identifier. ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding was OK, %ASN1_VALUE_NOT_VALID ++ * if @str is not a valid OID, %ASN1_MEM_ERROR if the @der ++ * vector isn't big enough and in this case @der_len will contain the ++ * length needed. ++ **/ ++int asn1_object_id_der(const char *str, unsigned char *der, int *der_len, unsigned flags) ++{ ++ unsigned char tag_der[MAX_TAG_LEN]; ++ int tag_len = 0, r; ++ int max_len = *der_len; ++ ++ *der_len = 0; ++ ++ _asn1_tag_der (ETYPE_CLASS (ASN1_ETYPE_OBJECT_ID), ETYPE_TAG (ASN1_ETYPE_OBJECT_ID), ++ tag_der, &tag_len); ++ ++ if (max_len > tag_len) ++ { ++ memcpy(der, tag_der, tag_len); ++ } ++ max_len -= tag_len; ++ der += tag_len; ++ ++ r = _asn1_object_id_der (str, der, &max_len); ++ if (r == ASN1_MEM_ERROR || r == ASN1_SUCCESS) ++ { ++ *der_len = max_len + tag_len; ++ } ++ ++ return r; ++} ++ ++static const unsigned char bit_mask[] = ++ { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80 }; ++ ++/** ++ * asn1_bit_der: ++ * @str: BIT string. ++ * @bit_len: number of meaningful bits in STR. ++ * @der: string returned. ++ * @der_len: number of meaningful bytes of DER ++ * (der[0]..der[ans_len-1]). ++ * ++ * Creates a length-value DER encoding for the input data ++ * as it would have been for a BIT STRING. ++ * The DER encoded data will be copied in @der. ++ * ++ * Note that the BIT STRING tag is not included in the output. ++ * ++ * This function does not return any value because it is expected ++ * that @der_len will contain enough bytes to store the string ++ * plus the DER encoding. The DER encoding size can be obtained using ++ * asn1_length_der(). ++ **/ ++void ++asn1_bit_der (const unsigned char *str, int bit_len, ++ unsigned char *der, int *der_len) ++{ ++ int len_len, len_byte, len_pad; ++ ++ if (der == NULL) ++ return; ++ ++ len_byte = bit_len >> 3; ++ len_pad = 8 - (bit_len & 7); ++ if (len_pad == 8) ++ len_pad = 0; ++ else ++ len_byte++; ++ asn1_length_der (len_byte + 1, der, &len_len); ++ der[len_len] = len_pad; ++ ++ if (str) ++ memcpy (der + len_len + 1, str, len_byte); ++ der[len_len + len_byte] &= bit_mask[len_pad]; ++ *der_len = len_byte + len_len + 1; ++} ++ ++ ++#if 0 ++/******************************************************/ ++/* Function : _asn1_complete_explicit_tag */ ++/* Description: add the length coding to the EXPLICIT */ ++/* tags. */ ++/* Parameters: */ ++/* node: pointer to the tree element. */ ++/* der: string with the DER coding of the whole tree*/ ++/* counter: number of meaningful bytes of DER */ ++/* (der[0]..der[*counter-1]). */ ++/* max_len: size of der vector */ ++/* Return: */ ++/* ASN1_MEM_ERROR if der vector isn't big enough, */ ++/* otherwise ASN1_SUCCESS. */ ++/******************************************************/ ++static int ++_asn1_complete_explicit_tag (asn1_node node, unsigned char *der, ++ int *counter, int *max_len) ++{ ++ asn1_node p; ++ int is_tag_implicit, len2, len3; ++ unsigned char temp[SIZEOF_UNSIGNED_INT]; ++ ++ if (der == NULL && *max_len > 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ is_tag_implicit = 0; ++ ++ if (node->type & CONST_TAG) ++ { ++ p = node->down; ++ if (p == NULL) ++ return ASN1_DER_ERROR; ++ /* When there are nested tags we must complete them reverse to ++ the order they were created. This is because completing a tag ++ modifies all data within it, including the incomplete tags ++ which store buffer positions -- simon@josefsson.org 2002-09-06 ++ */ ++ while (p->right) ++ p = p->right; ++ while (p && p != node->down->left) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_TAG) ++ { ++ if (p->type & CONST_EXPLICIT) ++ { ++ len2 = strtol (p->name, NULL, 10); ++ _asn1_set_name (p, NULL); ++ ++ asn1_length_der (*counter - len2, temp, &len3); ++ if (len3 <= (*max_len)) ++ { ++ memmove (der + len2 + len3, der + len2, ++ *counter - len2); ++ memcpy (der + len2, temp, len3); ++ } ++ *max_len -= len3; ++ *counter += len3; ++ is_tag_implicit = 0; ++ } ++ else ++ { /* CONST_IMPLICIT */ ++ if (!is_tag_implicit) ++ { ++ is_tag_implicit = 1; ++ } ++ } ++ } ++ p = p->left; ++ } ++ } ++ ++ if (*max_len < 0) ++ return ASN1_MEM_ERROR; ++ ++ return ASN1_SUCCESS; ++} ++#endif ++ ++const tag_and_class_st _asn1_tags[] = { ++ [ASN1_ETYPE_GENERALSTRING] = ++ {ASN1_TAG_GENERALSTRING, ASN1_CLASS_UNIVERSAL, "type:GENERALSTRING"}, ++ [ASN1_ETYPE_NUMERIC_STRING] = ++ {ASN1_TAG_NUMERIC_STRING, ASN1_CLASS_UNIVERSAL, "type:NUMERIC_STR"}, ++ [ASN1_ETYPE_IA5_STRING] = ++ {ASN1_TAG_IA5_STRING, ASN1_CLASS_UNIVERSAL, "type:IA5_STR"}, ++ [ASN1_ETYPE_TELETEX_STRING] = ++ {ASN1_TAG_TELETEX_STRING, ASN1_CLASS_UNIVERSAL, "type:TELETEX_STR"}, ++ [ASN1_ETYPE_PRINTABLE_STRING] = ++ {ASN1_TAG_PRINTABLE_STRING, ASN1_CLASS_UNIVERSAL, "type:PRINTABLE_STR"}, ++ [ASN1_ETYPE_UNIVERSAL_STRING] = ++ {ASN1_TAG_UNIVERSAL_STRING, ASN1_CLASS_UNIVERSAL, "type:UNIVERSAL_STR"}, ++ [ASN1_ETYPE_BMP_STRING] = ++ {ASN1_TAG_BMP_STRING, ASN1_CLASS_UNIVERSAL, "type:BMP_STR"}, ++ [ASN1_ETYPE_UTF8_STRING] = ++ {ASN1_TAG_UTF8_STRING, ASN1_CLASS_UNIVERSAL, "type:UTF8_STR"}, ++ [ASN1_ETYPE_VISIBLE_STRING] = ++ {ASN1_TAG_VISIBLE_STRING, ASN1_CLASS_UNIVERSAL, "type:VISIBLE_STR"}, ++ [ASN1_ETYPE_OCTET_STRING] = ++ {ASN1_TAG_OCTET_STRING, ASN1_CLASS_UNIVERSAL, "type:OCT_STR"}, ++ [ASN1_ETYPE_BIT_STRING] = ++ {ASN1_TAG_BIT_STRING, ASN1_CLASS_UNIVERSAL, "type:BIT_STR"}, ++ [ASN1_ETYPE_OBJECT_ID] = ++ {ASN1_TAG_OBJECT_ID, ASN1_CLASS_UNIVERSAL, "type:OBJ_ID"}, ++ [ASN1_ETYPE_NULL] = {ASN1_TAG_NULL, ASN1_CLASS_UNIVERSAL, "type:NULL"}, ++ [ASN1_ETYPE_BOOLEAN] = ++ {ASN1_TAG_BOOLEAN, ASN1_CLASS_UNIVERSAL, "type:BOOLEAN"}, ++ [ASN1_ETYPE_INTEGER] = ++ {ASN1_TAG_INTEGER, ASN1_CLASS_UNIVERSAL, "type:INTEGER"}, ++ [ASN1_ETYPE_ENUMERATED] = ++ {ASN1_TAG_ENUMERATED, ASN1_CLASS_UNIVERSAL, "type:ENUMERATED"}, ++ [ASN1_ETYPE_SEQUENCE] = ++ {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, ++ "type:SEQUENCE"}, ++ [ASN1_ETYPE_SEQUENCE_OF] = ++ {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, ++ "type:SEQ_OF"}, ++ [ASN1_ETYPE_SET] = ++ {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, "type:SET"}, ++ [ASN1_ETYPE_SET_OF] = ++ {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, ++ "type:SET_OF"}, ++ [ASN1_ETYPE_GENERALIZED_TIME] = ++ {ASN1_TAG_GENERALIZEDTime, ASN1_CLASS_UNIVERSAL, "type:GENERALIZED_TIME"}, ++ [ASN1_ETYPE_UTC_TIME] = ++ {ASN1_TAG_UTCTime, ASN1_CLASS_UNIVERSAL, "type:UTC_TIME"}, ++}; ++ ++unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]); ++ ++ ++#if 0 ++/******************************************************/ ++/* Function : _asn1_insert_tag_der */ ++/* Description: creates the DER coding of tags of one */ ++/* NODE. */ ++/* Parameters: */ ++/* node: pointer to the tree element. */ ++/* der: string returned */ ++/* counter: number of meaningful bytes of DER */ ++/* (counter[0]..der[*counter-1]). */ ++/* max_len: size of der vector */ ++/* Return: */ ++/* ASN1_GENERIC_ERROR if the type is unknown, */ ++/* ASN1_MEM_ERROR if der vector isn't big enough, */ ++/* otherwise ASN1_SUCCESS. */ ++/******************************************************/ ++static int ++_asn1_insert_tag_der (asn1_node node, unsigned char *der, int *counter, ++ int *max_len) ++{ ++ asn1_node p; ++ int tag_len, is_tag_implicit; ++ unsigned char class, class_implicit = 0, temp[MAX(SIZEOF_UNSIGNED_INT * 3 + 1, LTOSTR_MAX_SIZE)]; ++ unsigned long tag_implicit = 0; ++ unsigned char tag_der[MAX_TAG_LEN]; ++ ++ is_tag_implicit = 0; ++ ++ if (node->type & CONST_TAG) ++ { ++ p = node->down; ++ while (p) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_TAG) ++ { ++ if (p->type & CONST_APPLICATION) ++ class = ASN1_CLASS_APPLICATION; ++ else if (p->type & CONST_UNIVERSAL) ++ class = ASN1_CLASS_UNIVERSAL; ++ else if (p->type & CONST_PRIVATE) ++ class = ASN1_CLASS_PRIVATE; ++ else ++ class = ASN1_CLASS_CONTEXT_SPECIFIC; ++ ++ if (p->type & CONST_EXPLICIT) ++ { ++ if (is_tag_implicit) ++ _asn1_tag_der (class_implicit, tag_implicit, tag_der, ++ &tag_len); ++ else ++ _asn1_tag_der (class | ASN1_CLASS_STRUCTURED, ++ _asn1_strtoul (p->value, NULL, 10), ++ tag_der, &tag_len); ++ ++ *max_len -= tag_len; ++ if (der && *max_len >= 0) ++ memcpy (der + *counter, tag_der, tag_len); ++ *counter += tag_len; ++ ++ _asn1_ltostr (*counter, (char *) temp); ++ _asn1_set_name (p, (const char *) temp); ++ ++ is_tag_implicit = 0; ++ } ++ else ++ { /* CONST_IMPLICIT */ ++ if (!is_tag_implicit) ++ { ++ if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) || ++ (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF) ++ || (type_field (node->type) == ASN1_ETYPE_SET) ++ || (type_field (node->type) == ASN1_ETYPE_SET_OF)) ++ class |= ASN1_CLASS_STRUCTURED; ++ class_implicit = class; ++ tag_implicit = _asn1_strtoul (p->value, NULL, 10); ++ is_tag_implicit = 1; ++ } ++ } ++ } ++ p = p->right; ++ } ++ } ++ ++ if (is_tag_implicit) ++ { ++ _asn1_tag_der (class_implicit, tag_implicit, tag_der, &tag_len); ++ } ++ else ++ { ++ unsigned type = type_field (node->type); ++ switch (type) ++ { ++ CASE_HANDLED_ETYPES: ++ _asn1_tag_der (_asn1_tags[type].class, _asn1_tags[type].tag, ++ tag_der, &tag_len); ++ break; ++ case ASN1_ETYPE_TAG: ++ case ASN1_ETYPE_CHOICE: ++ case ASN1_ETYPE_ANY: ++ tag_len = 0; ++ break; ++ default: ++ return ASN1_GENERIC_ERROR; ++ } ++ } ++ ++ *max_len -= tag_len; ++ if (der && *max_len >= 0) ++ memcpy (der + *counter, tag_der, tag_len); ++ *counter += tag_len; ++ ++ if (*max_len < 0) ++ return ASN1_MEM_ERROR; ++ ++ return ASN1_SUCCESS; ++} ++ ++/******************************************************/ ++/* Function : _asn1_ordering_set */ ++/* Description: puts the elements of a SET type in */ ++/* the correct order according to DER rules. */ ++/* Parameters: */ ++/* der: string with the DER coding. */ ++/* node: pointer to the SET element. */ ++/* Return: */ ++/* ASN1_SUCCESS if successful */ ++/* or an error value. */ ++/******************************************************/ ++static int ++_asn1_ordering_set (unsigned char *der, int der_len, asn1_node node) ++{ ++ struct vet ++ { ++ int end; ++ unsigned long value; ++ struct vet *next, *prev; ++ }; ++ ++ int counter, len, len2; ++ struct vet *first, *last, *p_vet, *p2_vet; ++ asn1_node p; ++ unsigned char class, *temp; ++ unsigned long tag, t; ++ int err; ++ ++ counter = 0; ++ ++ if (type_field (node->type) != ASN1_ETYPE_SET) ++ return ASN1_VALUE_NOT_VALID; ++ ++ p = node->down; ++ while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) || ++ (type_field (p->type) == ASN1_ETYPE_SIZE))) ++ p = p->right; ++ ++ if ((p == NULL) || (p->right == NULL)) ++ return ASN1_SUCCESS; ++ ++ first = last = NULL; ++ while (p) ++ { ++ p_vet = malloc (sizeof (struct vet)); ++ if (p_vet == NULL) ++ { ++ err = ASN1_MEM_ALLOC_ERROR; ++ goto error; ++ } ++ ++ p_vet->next = NULL; ++ p_vet->prev = last; ++ if (first == NULL) ++ first = p_vet; ++ else ++ last->next = p_vet; ++ last = p_vet; ++ ++ /* tag value calculation */ ++ err = asn1_get_tag_der (der + counter, der_len - counter, &class, &len2, ++ &tag); ++ if (err != ASN1_SUCCESS) ++ goto error; ++ ++ t = ((unsigned int)class) << 24; ++ p_vet->value = t | tag; ++ counter += len2; ++ ++ /* extraction and length */ ++ len2 = asn1_get_length_der (der + counter, der_len - counter, &len); ++ if (len2 < 0) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ counter += len + len2; ++ ++ p_vet->end = counter; ++ p = p->right; ++ } ++ ++ p_vet = first; ++ ++ while (p_vet) ++ { ++ p2_vet = p_vet->next; ++ counter = 0; ++ while (p2_vet) ++ { ++ if (p_vet->value > p2_vet->value) ++ { ++ /* change position */ ++ temp = malloc (p_vet->end - counter); ++ if (temp == NULL) ++ { ++ err = ASN1_MEM_ALLOC_ERROR; ++ goto error; ++ } ++ ++ memcpy (temp, der + counter, p_vet->end - counter); ++ memcpy (der + counter, der + p_vet->end, ++ p2_vet->end - p_vet->end); ++ memcpy (der + counter + p2_vet->end - p_vet->end, temp, ++ p_vet->end - counter); ++ free (temp); ++ ++ tag = p_vet->value; ++ p_vet->value = p2_vet->value; ++ p2_vet->value = tag; ++ ++ p_vet->end = counter + (p2_vet->end - p_vet->end); ++ } ++ counter = p_vet->end; ++ ++ p2_vet = p2_vet->next; ++ p_vet = p_vet->next; ++ } ++ ++ if (p_vet != first) ++ p_vet->prev->next = NULL; ++ else ++ first = NULL; ++ free (p_vet); ++ p_vet = first; ++ } ++ return ASN1_SUCCESS; ++ ++error: ++ while (first != NULL) ++ { ++ p_vet = first; ++ first = first->next; ++ free(p_vet); ++ } ++ return err; ++} ++ ++struct vet ++{ ++ unsigned char *ptr; ++ int size; ++}; ++ ++static int setof_compar(const void *_e1, const void *_e2) ++{ ++ unsigned length; ++ const struct vet *e1 = _e1, *e2 = _e2; ++ int rval; ++ ++ /* The encodings of the component values of a set-of value shall ++ * appear in ascending order, the encodings being compared ++ * as octet strings with the shorter components being ++ * padded at their trailing end with 0-octets. ++ * The padding octets are for comparison purposes and ++ * do not appear in the encodings. ++ */ ++ length = MIN(e1->size, e2->size); ++ ++ rval = memcmp(e1->ptr, e2->ptr, length); ++ if (rval == 0 && e1->size != e2->size) ++ { ++ if (e1->size > e2->size) ++ rval = 1; ++ else if (e2->size > e1->size) ++ rval = -1; ++ } ++ ++ return rval; ++} ++ ++/******************************************************/ ++/* Function : _asn1_ordering_set_of */ ++/* Description: puts the elements of a SET OF type in */ ++/* the correct order according to DER rules. */ ++/* Parameters: */ ++/* der: string with the DER coding. */ ++/* node: pointer to the SET OF element. */ ++/* Return: */ ++/* ASN1_SUCCESS if successful */ ++/* or an error value. */ ++/******************************************************/ ++static int ++_asn1_ordering_set_of (unsigned char *der, int der_len, asn1_node node) ++{ ++ int counter, len, len2; ++ struct vet *list = NULL, *tlist; ++ unsigned list_size = 0; ++ struct vet *p_vet; ++ asn1_node p; ++ unsigned char class; ++ unsigned i; ++ unsigned char *out = NULL; ++ int err; ++ ++ if (der == NULL) ++ return ASN1_VALUE_NOT_VALID; ++ ++ counter = 0; ++ ++ if (type_field (node->type) != ASN1_ETYPE_SET_OF) ++ return ASN1_VALUE_NOT_VALID; ++ ++ p = node->down; ++ while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) || ++ (type_field (p->type) == ASN1_ETYPE_SIZE))) ++ p = p->right; ++ if (p == NULL) ++ return ASN1_VALUE_NOT_VALID; ++ p = p->right; ++ ++ if ((p == NULL) || (p->right == NULL)) ++ return ASN1_SUCCESS; ++ ++ while (p) ++ { ++ list_size++; ++ tlist = realloc (list, list_size*sizeof(struct vet)); ++ if (tlist == NULL) ++ { ++ err = ASN1_MEM_ALLOC_ERROR; ++ goto error; ++ } ++ list = tlist; ++ p_vet = &list[list_size-1]; ++ ++ p_vet->ptr = der+counter; ++ p_vet->size = 0; ++ ++ /* extraction of tag and length */ ++ if (der_len - counter > 0) ++ { ++ err = asn1_get_tag_der (der + counter, der_len - counter, &class, ++ &len, NULL); ++ if (err != ASN1_SUCCESS) ++ goto error; ++ counter += len; ++ p_vet->size += len; ++ ++ len2 = asn1_get_length_der (der + counter, der_len - counter, &len); ++ if (len2 < 0) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ counter += len + len2; ++ p_vet->size += len + len2; ++ ++ } ++ else ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ p = p->right; ++ } ++ ++ if (counter > der_len) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ ++ qsort(list, list_size, sizeof(struct vet), setof_compar); ++ ++ out = malloc(der_len); ++ if (out == NULL) ++ { ++ err = ASN1_MEM_ERROR; ++ goto error; ++ } ++ ++ /* the sum of p_vet->size == der_len */ ++ counter = 0; ++ for (i = 0; i < list_size; i++) ++ { ++ p_vet = &list[i]; ++ memcpy(out+counter, p_vet->ptr, p_vet->size); ++ counter += p_vet->size; ++ } ++ memcpy(der, out, der_len); ++ free(out); ++ ++ err = ASN1_SUCCESS; ++ ++error: ++ free(list); ++ return err; ++} ++ ++/** ++ * asn1_der_coding: ++ * @element: pointer to an ASN1 element ++ * @name: the name of the structure you want to encode (it must be ++ * inside *POINTER). ++ * @ider: vector that will contain the DER encoding. DER must be a ++ * pointer to memory cells already allocated. ++ * @len: number of bytes of *@ider: @ider[0]..@ider[len-1], Initialy ++ * holds the sizeof of der vector. ++ * @ErrorDescription: return the error description or an empty ++ * string if success. ++ * ++ * Creates the DER encoding for the NAME structure (inside *POINTER ++ * structure). ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND ++ * if @name is not a valid element, %ASN1_VALUE_NOT_FOUND if there ++ * is an element without a value, %ASN1_MEM_ERROR if the @ider ++ * vector isn't big enough and in this case @len will contain the ++ * length needed. ++ **/ ++int ++asn1_der_coding (asn1_node_const element, const char *name, void *ider, int *len, ++ char *ErrorDescription) ++{ ++ asn1_node node, p, p2; ++ unsigned char temp[MAX(LTOSTR_MAX_SIZE, SIZEOF_UNSIGNED_LONG_INT * 3 + 1)]; ++ int counter, counter_old, len2, len3, move, max_len, max_len_old; ++ int err; ++ unsigned char *der = ider; ++ ++ if (ErrorDescription) ++ ErrorDescription[0] = 0; ++ ++ node = asn1_find_node (element, name); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ /* Node is now a locally allocated variable. ++ * That is because in some point we modify the ++ * structure, and I don't know why! --nmav ++ */ ++ node = _asn1_copy_structure3 (node); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ max_len = *len; ++ ++ if (der == NULL && max_len > 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ counter = 0; ++ move = DOWN; ++ p = node; ++ ++ while (1) ++ { ++ ++ counter_old = counter; ++ max_len_old = max_len; ++ if (move != UP) ++ { ++ p->start = counter; ++ err = _asn1_insert_tag_der (p, der, &counter, &max_len); ++ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) ++ goto error; ++ } ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_NULL: ++ max_len--; ++ if (der != NULL && max_len >= 0) ++ der[counter] = 0; ++ counter++; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_BOOLEAN: ++ if ((p->type & CONST_DEFAULT) && (p->value == NULL)) ++ { ++ counter = counter_old; ++ max_len = max_len_old; ++ } ++ else ++ { ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ++ ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ max_len -= 2; ++ if (der != NULL && max_len >= 0) ++ { ++ der[counter++] = 1; ++ if (p->value[0] == 'F') ++ der[counter++] = 0; ++ else ++ der[counter++] = 0xFF; ++ } ++ else ++ counter += 2; ++ } ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_INTEGER: ++ case ASN1_ETYPE_ENUMERATED: ++ if ((p->type & CONST_DEFAULT) && (p->value == NULL)) ++ { ++ counter = counter_old; ++ max_len = max_len_old; ++ } ++ else ++ { ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ++ ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ len2 = asn1_get_length_der (p->value, p->value_len, &len3); ++ if (len2 < 0) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ max_len -= len2 + len3; ++ if (der != NULL && max_len >= 0) ++ memcpy (der + counter, p->value, len3 + len2); ++ counter += len3 + len2; ++ } ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_OBJECT_ID: ++ if ((p->type & CONST_DEFAULT) && (p->value == NULL)) ++ { ++ counter = counter_old; ++ max_len = max_len_old; ++ } ++ else ++ { ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ++ ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ len2 = max_len; ++ err = _asn1_object_id_der ((char*)p->value, der + counter, &len2); ++ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) ++ goto error; ++ ++ max_len -= len2; ++ counter += len2; ++ } ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ case ASN1_ETYPE_UTC_TIME: ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ len2 = max_len; ++ err = _asn1_time_der (p->value, p->value_len, der + counter, &len2); ++ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) ++ goto error; ++ ++ max_len -= len2; ++ counter += len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_OCTET_STRING: ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ case ASN1_ETYPE_BIT_STRING: ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ len2 = asn1_get_length_der (p->value, p->value_len, &len3); ++ if (len2 < 0) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ max_len -= len2 + len3; ++ if (der != NULL && max_len >= 0) ++ memcpy (der + counter, p->value, len3 + len2); ++ counter += len3 + len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_SEQUENCE: ++ case ASN1_ETYPE_SET: ++ if (move != UP) ++ { ++ p->tmp_ival = counter; ++ if (p->down == NULL) ++ { ++ move = UP; ++ continue; ++ } ++ else ++ { ++ p2 = p->down; ++ while (p2 && (type_field (p2->type) == ASN1_ETYPE_TAG)) ++ p2 = p2->right; ++ if (p2) ++ { ++ p = p2; ++ move = RIGHT; ++ continue; ++ } ++ move = UP; ++ continue; ++ } ++ } ++ else ++ { /* move==UP */ ++ len2 = p->tmp_ival; ++ p->tmp_ival = 0; ++ if ((type_field (p->type) == ASN1_ETYPE_SET) && (max_len >= 0)) ++ { ++ err = _asn1_ordering_set (der + len2, counter - len2, p); ++ if (err != ASN1_SUCCESS) ++ goto error; ++ } ++ asn1_length_der (counter - len2, temp, &len3); ++ max_len -= len3; ++ if (der != NULL && max_len >= 0) ++ { ++ memmove (der + len2 + len3, der + len2, counter - len2); ++ memcpy (der + len2, temp, len3); ++ } ++ counter += len3; ++ move = RIGHT; ++ } ++ break; ++ case ASN1_ETYPE_SEQUENCE_OF: ++ case ASN1_ETYPE_SET_OF: ++ if (move != UP) ++ { ++ p->tmp_ival = counter; ++ p = p->down; ++ while ((type_field (p->type) == ASN1_ETYPE_TAG) ++ || (type_field (p->type) == ASN1_ETYPE_SIZE)) ++ p = p->right; ++ if (p->right) ++ { ++ p = p->right; ++ move = RIGHT; ++ continue; ++ } ++ else ++ p = _asn1_find_up (p); ++ move = UP; ++ } ++ if (move == UP) ++ { ++ len2 = p->tmp_ival; ++ p->tmp_ival = 0; ++ if ((type_field (p->type) == ASN1_ETYPE_SET_OF) ++ && (counter - len2 > 0) && (max_len >= 0)) ++ { ++ err = _asn1_ordering_set_of (der + len2, counter - len2, p); ++ if (err != ASN1_SUCCESS) ++ goto error; ++ } ++ asn1_length_der (counter - len2, temp, &len3); ++ max_len -= len3; ++ if (der != NULL && max_len >= 0) ++ { ++ memmove (der + len2 + len3, der + len2, counter - len2); ++ memcpy (der + len2, temp, len3); ++ } ++ counter += len3; ++ move = RIGHT; ++ } ++ break; ++ case ASN1_ETYPE_ANY: ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ len2 = asn1_get_length_der (p->value, p->value_len, &len3); ++ if (len2 < 0) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ max_len -= len2; ++ if (der != NULL && max_len >= 0) ++ memcpy (der + counter, p->value + len3, len2); ++ counter += len2; ++ move = RIGHT; ++ break; ++ default: ++ move = (move == UP) ? RIGHT : DOWN; ++ break; ++ } ++ ++ if ((move != DOWN) && (counter != counter_old)) ++ { ++ p->end = counter - 1; ++ err = _asn1_complete_explicit_tag (p, der, &counter, &max_len); ++ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) ++ goto error; ++ } ++ ++ if (p == node && move != DOWN) ++ break; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ if (move == RIGHT) ++ { ++ if (p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ *len = counter; ++ ++ if (max_len < 0) ++ { ++ err = ASN1_MEM_ERROR; ++ goto error; ++ } ++ ++ err = ASN1_SUCCESS; ++ ++error: ++ asn1_delete_structure (&node); ++ return err; ++} ++ ++#endif +\ No newline at end of file +diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c +new file mode 100644 +index 000000000..7856858b2 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/decoding.c +@@ -0,0 +1,2481 @@ ++/* ++ * Copyright (C) 2002-2016 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++ ++/*****************************************************/ ++/* File: decoding.c */ ++/* Description: Functions to manage DER decoding */ ++/*****************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define c_isdigit grub_isdigit ++ ++#ifdef DEBUG ++# define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__) ++#else ++# define warn() ++#endif ++ ++#define IS_ERR(len, flags) (len < -1 || ((flags & ASN1_DECODE_FLAG_STRICT_DER) && len < 0)) ++ ++#define HAVE_TWO(x) (x>=2?1:0) ++ ++/* Decoding flags (dflags) used in several decoding functions. ++ * DECODE_FLAG_HAVE_TAG: The provided buffer includes a tag ++ * DECODE_FLAG_CONSTRUCTED: The provided buffer is of indefinite encoding (useful ++ * when no tags are present). ++ * DECODE_FLAG_LEVEL1: Internal flag to indicate a level of recursion for BER strings. ++ * DECODE_FLAG_LEVEL2: Internal flag to indicate two levels of recursion for BER strings. ++ * DECODE_FLAG_LEVEL3: Internal flag to indicate three levels of recursion for BER strings. ++ * This is the maximum levels of recursion possible to prevent stack ++ * exhaustion. ++ */ ++ ++#define DECODE_FLAG_HAVE_TAG 1 ++#define DECODE_FLAG_CONSTRUCTED (1<<1) ++#define DECODE_FLAG_LEVEL1 (1<<2) ++#define DECODE_FLAG_LEVEL2 (1<<3) ++#define DECODE_FLAG_LEVEL3 (1<<4) ++ ++#define DECR_LEN(l, s) do { \ ++ l -= s; \ ++ if (l < 0) { \ ++ warn(); \ ++ result = ASN1_DER_ERROR; \ ++ goto cleanup; \ ++ } \ ++ } while (0) ++ ++static int ++_asn1_get_indefinite_length_string (const unsigned char *der, int der_len, int *len); ++ ++static int ++_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, unsigned char **str, ++ unsigned int *str_len, unsigned int *ber_len, ++ unsigned dflags); ++ ++static int ++_asn1_decode_simple_der (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, const unsigned char **str, ++ unsigned int *str_len, unsigned dflags); ++ ++static void ++_asn1_error_description_tag_error (asn1_node node, char *ErrorDescription) ++{ ++ ++ Estrcpy (ErrorDescription, ":: tag error near element '"); ++ _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription), ++ ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40); ++ Estrcat (ErrorDescription, "'"); ++ ++} ++ ++/** ++ * asn1_get_length_der: ++ * @der: DER data to decode. ++ * @der_len: Length of DER data to decode. ++ * @len: Output variable containing the length of the DER length field. ++ * ++ * Extract a length field from DER data. ++ * ++ * Returns: Return the decoded length value, or -1 on indefinite ++ * length, or -2 when the value was too big to fit in a int, or -4 ++ * when the decoded length value plus @len would exceed @der_len. ++ **/ ++long ++asn1_get_length_der (const unsigned char *der, int der_len, int *len) ++{ ++ unsigned int ans; ++ int k, punt, sum; ++ ++ *len = 0; ++ if (der_len <= 0) ++ return 0; ++ ++ if (!(der[0] & 128)) ++ { ++ /* short form */ ++ *len = 1; ++ ans = der[0]; ++ } ++ else ++ { ++ /* Long form */ ++ k = der[0] & 0x7F; ++ punt = 1; ++ if (k) ++ { /* definite length method */ ++ ans = 0; ++ while (punt <= k && punt < der_len) ++ { ++ if (INT_MULTIPLY_OVERFLOW (ans, 256)) ++ return -2; ++ ans *= 256; ++ ++ if (INT_ADD_OVERFLOW (ans, ((unsigned) der[punt]))) ++ return -2; ++ ans += der[punt]; ++ punt++; ++ } ++ } ++ else ++ { /* indefinite length method */ ++ *len = punt; ++ return -1; ++ } ++ ++ *len = punt; ++ } ++ ++ sum = ans; ++ if (ans >= INT_MAX || INT_ADD_OVERFLOW (sum, (*len))) ++ return -2; ++ sum += *len; ++ ++ if (sum > der_len) ++ return -4; ++ ++ return ans; ++} ++ ++/** ++ * asn1_get_tag_der: ++ * @der: DER data to decode. ++ * @der_len: Length of DER data to decode. ++ * @cls: Output variable containing decoded class. ++ * @len: Output variable containing the length of the DER TAG data. ++ * @tag: Output variable containing the decoded tag (may be %NULL). ++ * ++ * Decode the class and TAG from DER code. ++ * ++ * Returns: Returns %ASN1_SUCCESS on success, or an error. ++ **/ ++int ++asn1_get_tag_der (const unsigned char *der, int der_len, ++ unsigned char *cls, int *len, unsigned long *tag) ++{ ++ unsigned int ris; ++ int punt; ++ ++ if (der == NULL || der_len < 2 || len == NULL) ++ return ASN1_DER_ERROR; ++ ++ *cls = der[0] & 0xE0; ++ if ((der[0] & 0x1F) != 0x1F) ++ { ++ /* short form */ ++ *len = 1; ++ ris = der[0] & 0x1F; ++ } ++ else ++ { ++ /* Long form */ ++ punt = 1; ++ ris = 0; ++ while (punt < der_len && der[punt] & 128) ++ { ++ ++ if (INT_MULTIPLY_OVERFLOW (ris, 128)) ++ return ASN1_DER_ERROR; ++ ris *= 128; ++ ++ if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F)))) ++ return ASN1_DER_ERROR; ++ ris += (der[punt] & 0x7F); ++ punt++; ++ } ++ ++ if (punt >= der_len) ++ return ASN1_DER_ERROR; ++ ++ if (INT_MULTIPLY_OVERFLOW (ris, 128)) ++ return ASN1_DER_ERROR; ++ ris *= 128; ++ ++ if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F)))) ++ return ASN1_DER_ERROR; ++ ris += (der[punt] & 0x7F); ++ punt++; ++ ++ *len = punt; ++ } ++ ++ if (tag) ++ *tag = ris; ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_get_length_ber: ++ * @ber: BER data to decode. ++ * @ber_len: Length of BER data to decode. ++ * @len: Output variable containing the length of the BER length field. ++ * ++ * Extract a length field from BER data. The difference to ++ * asn1_get_length_der() is that this function will return a length ++ * even if the value has indefinite encoding. ++ * ++ * Returns: Return the decoded length value, or negative value when ++ * the value was too big. ++ * ++ * Since: 2.0 ++ **/ ++long ++asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len) ++{ ++ int ret; ++ long err; ++ ++ ret = asn1_get_length_der (ber, ber_len, len); ++ ++ if (ret == -1 && ber_len > 1) ++ { /* indefinite length method */ ++ err = _asn1_get_indefinite_length_string (ber + 1, ber_len-1, &ret); ++ if (err != ASN1_SUCCESS) ++ return -3; ++ } ++ ++ return ret; ++} ++ ++/** ++ * asn1_get_octet_der: ++ * @der: DER data to decode containing the OCTET SEQUENCE. ++ * @der_len: The length of the @der data to decode. ++ * @ret_len: Output variable containing the encoded length of the DER data. ++ * @str: Pre-allocated output buffer to put decoded OCTET SEQUENCE in. ++ * @str_size: Length of pre-allocated output buffer. ++ * @str_len: Output variable containing the length of the contents of the OCTET SEQUENCE. ++ * ++ * Extract an OCTET SEQUENCE from DER data. Note that this function ++ * expects the DER data past the tag field, i.e., the length and ++ * content octets. ++ * ++ * Returns: Returns %ASN1_SUCCESS on success, or an error. ++ **/ ++int ++asn1_get_octet_der (const unsigned char *der, int der_len, ++ int *ret_len, unsigned char *str, int str_size, ++ int *str_len) ++{ ++ int len_len = 0; ++ ++ if (der_len <= 0) ++ return ASN1_GENERIC_ERROR; ++ ++ *str_len = asn1_get_length_der (der, der_len, &len_len); ++ ++ if (*str_len < 0) ++ return ASN1_DER_ERROR; ++ ++ *ret_len = *str_len + len_len; ++ if (str_size >= *str_len) ++ { ++ if (*str_len > 0 && str != NULL) ++ memcpy (str, der + len_len, *str_len); ++ } ++ else ++ { ++ return ASN1_MEM_ERROR; ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/*- ++ * _asn1_get_time_der: ++ * @type: %ASN1_ETYPE_GENERALIZED_TIME or %ASN1_ETYPE_UTC_TIME ++ * @der: DER data to decode containing the time ++ * @der_len: Length of DER data to decode. ++ * @ret_len: Output variable containing the length of the DER data. ++ * @str: Pre-allocated output buffer to put the textual time in. ++ * @str_size: Length of pre-allocated output buffer. ++ * @flags: Zero or %ASN1_DECODE_FLAG_STRICT_DER ++ * ++ * Performs basic checks in the DER encoded time object and returns its textual form. ++ * The textual form will be in the YYYYMMDD000000Z format for GeneralizedTime ++ * and YYMMDD000000Z for UTCTime. ++ * ++ * Returns: %ASN1_SUCCESS on success, or an error. ++ -*/ ++static int ++_asn1_get_time_der (unsigned type, const unsigned char *der, int der_len, int *ret_len, ++ char *str, int str_size, unsigned flags) ++{ ++ int len_len, str_len; ++ unsigned i; ++ unsigned sign_count = 0; ++ unsigned dot_count = 0; ++ const unsigned char *p; ++ ++ if (der_len <= 0 || str == NULL) ++ return ASN1_DER_ERROR; ++ ++ str_len = asn1_get_length_der (der, der_len, &len_len); ++ if (str_len <= 0 || str_size < str_len) ++ return ASN1_DER_ERROR; ++ ++ /* perform some sanity checks on the data */ ++ if (str_len < 8) ++ { ++ warn(); ++ return ASN1_TIME_ENCODING_ERROR; ++ } ++ ++ if ((flags & ASN1_DECODE_FLAG_STRICT_DER) && !(flags & ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME)) ++ { ++ p = &der[len_len]; ++ for (i=0;i<(unsigned)(str_len-1);i++) ++ { ++ if (c_isdigit(p[i]) == 0) ++ { ++ if (type == ASN1_ETYPE_GENERALIZED_TIME) ++ { ++ /* tolerate lax encodings */ ++ if (p[i] == '.' && dot_count == 0) ++ { ++ dot_count++; ++ continue; ++ } ++ ++ /* This is not really valid DER, but there are ++ * structures using that */ ++ if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) && ++ (p[i] == '+' || p[i] == '-') && sign_count == 0) ++ { ++ sign_count++; ++ continue; ++ } ++ } ++ ++ warn(); ++ return ASN1_TIME_ENCODING_ERROR; ++ } ++ } ++ ++ if (sign_count == 0 && p[str_len-1] != 'Z') ++ { ++ warn(); ++ return ASN1_TIME_ENCODING_ERROR; ++ } ++ } ++ memcpy (str, der + len_len, str_len); ++ str[str_len] = 0; ++ *ret_len = str_len + len_len; ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_get_object_id_der: ++ * @der: DER data to decode containing the OBJECT IDENTIFIER ++ * @der_len: Length of DER data to decode. ++ * @ret_len: Output variable containing the length of the DER data. ++ * @str: Pre-allocated output buffer to put the textual object id in. ++ * @str_size: Length of pre-allocated output buffer. ++ * ++ * Converts a DER encoded object identifier to its textual form. This ++ * function expects the DER object identifier without the tag. ++ * ++ * Returns: %ASN1_SUCCESS on success, or an error. ++ **/ ++int ++asn1_get_object_id_der (const unsigned char *der, int der_len, int *ret_len, ++ char *str, int str_size) ++{ ++ int len_len, len, k; ++ int leading, parsed; ++ char temp[LTOSTR_MAX_SIZE]; ++ uint64_t val, val1, val0; ++ ++ *ret_len = 0; ++ if (str && str_size > 0) ++ str[0] = 0; /* no oid */ ++ ++ if (str == NULL || der_len <= 0) ++ return ASN1_GENERIC_ERROR; ++ ++ len = asn1_get_length_der (der, der_len, &len_len); ++ ++ if (len <= 0 || len + len_len > der_len) ++ return ASN1_DER_ERROR; ++ ++ /* leading octet can never be 0x80 */ ++ if (der[len_len] == 0x80) ++ return ASN1_DER_ERROR; ++ ++ val0 = 0; ++ ++ for (k = 0; k < len; k++) ++ { ++ if (INT_LEFT_SHIFT_OVERFLOW (val0, 7)) ++ return ASN1_DER_ERROR; ++ ++ val0 <<= 7; ++ val0 |= der[len_len + k] & 0x7F; ++ if (!(der[len_len + k] & 0x80)) ++ break; ++ } ++ parsed = ++k; ++ ++ /* val0 = (X*40) + Y, X={0,1,2}, Y<=39 when X={0,1} */ ++ /* X = val, Y = val1 */ ++ ++ /* check if X == 0 */ ++ val = 0; ++ val1 = val0; ++ if (val1 > 39) ++ { ++ val = 1; ++ val1 = val0 - 40; ++ if (val1 > 39) ++ { ++ val = 2; ++ val1 = val0 - 80; ++ } ++ } ++ ++ _asn1_str_cpy (str, str_size, _asn1_ltostr (val, temp)); ++ _asn1_str_cat (str, str_size, "."); ++ _asn1_str_cat (str, str_size, _asn1_ltostr (val1, temp)); ++ ++ val = 0; ++ leading = 1; ++ for (k = parsed; k < len; k++) ++ { ++ /* X.690 mandates that the leading byte must never be 0x80 ++ */ ++ if (leading != 0 && der[len_len + k] == 0x80) ++ return ASN1_DER_ERROR; ++ leading = 0; ++ ++ /* check for wrap around */ ++ if (INT_LEFT_SHIFT_OVERFLOW (val, 7)) ++ return ASN1_DER_ERROR; ++ ++ val = val << 7; ++ val |= der[len_len + k] & 0x7F; ++ ++ if (!(der[len_len + k] & 0x80)) ++ { ++ _asn1_str_cat (str, str_size, "."); ++ _asn1_str_cat (str, str_size, _asn1_ltostr (val, temp)); ++ val = 0; ++ leading = 1; ++ } ++ } ++ ++ if (INT_ADD_OVERFLOW (len, len_len)) ++ return ASN1_DER_ERROR; ++ ++ *ret_len = len + len_len; ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_get_bit_der: ++ * @der: DER data to decode containing the BIT SEQUENCE. ++ * @der_len: Length of DER data to decode. ++ * @ret_len: Output variable containing the length of the DER data. ++ * @str: Pre-allocated output buffer to put decoded BIT SEQUENCE in. ++ * @str_size: Length of pre-allocated output buffer. ++ * @bit_len: Output variable containing the size of the BIT SEQUENCE. ++ * ++ * Extract a BIT SEQUENCE from DER data. ++ * ++ * Returns: %ASN1_SUCCESS on success, or an error. ++ **/ ++int ++asn1_get_bit_der (const unsigned char *der, int der_len, ++ int *ret_len, unsigned char *str, int str_size, ++ int *bit_len) ++{ ++ int len_len = 0, len_byte; ++ ++ if (der_len <= 0) ++ return ASN1_GENERIC_ERROR; ++ ++ len_byte = asn1_get_length_der (der, der_len, &len_len) - 1; ++ if (len_byte < 0) ++ return ASN1_DER_ERROR; ++ ++ *ret_len = len_byte + len_len + 1; ++ *bit_len = len_byte * 8 - der[len_len]; ++ ++ if (*bit_len < 0) ++ return ASN1_DER_ERROR; ++ ++ if (str_size >= len_byte) ++ { ++ if (len_byte > 0 && str) ++ memcpy (str, der + len_len + 1, len_byte); ++ } ++ else ++ { ++ return ASN1_MEM_ERROR; ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++/* tag_len: the total tag length (explicit+inner) ++ * inner_tag_len: the inner_tag length ++ */ ++static int ++_asn1_extract_tag_der (asn1_node node, const unsigned char *der, int der_len, ++ int *tag_len, int *inner_tag_len, unsigned flags) ++{ ++ asn1_node p; ++ int counter, len2, len3, is_tag_implicit; ++ int result; ++ unsigned long tag, tag_implicit = 0; ++ unsigned char class, class2, class_implicit = 0; ++ ++ if (der_len <= 0) ++ return ASN1_GENERIC_ERROR; ++ ++ counter = is_tag_implicit = 0; ++ ++ if (node->type & CONST_TAG) ++ { ++ p = node->down; ++ while (p) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_TAG) ++ { ++ if (p->type & CONST_APPLICATION) ++ class2 = ASN1_CLASS_APPLICATION; ++ else if (p->type & CONST_UNIVERSAL) ++ class2 = ASN1_CLASS_UNIVERSAL; ++ else if (p->type & CONST_PRIVATE) ++ class2 = ASN1_CLASS_PRIVATE; ++ else ++ class2 = ASN1_CLASS_CONTEXT_SPECIFIC; ++ ++ if (p->type & CONST_EXPLICIT) ++ { ++ if (asn1_get_tag_der ++ (der + counter, der_len, &class, &len2, ++ &tag) != ASN1_SUCCESS) ++ return ASN1_DER_ERROR; ++ ++ DECR_LEN(der_len, len2); ++ counter += len2; ++ ++ if (flags & ASN1_DECODE_FLAG_STRICT_DER) ++ len3 = ++ asn1_get_length_der (der + counter, der_len, ++ &len2); ++ else ++ len3 = ++ asn1_get_length_ber (der + counter, der_len, ++ &len2); ++ if (len3 < 0) ++ return ASN1_DER_ERROR; ++ ++ DECR_LEN(der_len, len2); ++ counter += len2; ++ ++ if (!is_tag_implicit) ++ { ++ if ((class != (class2 | ASN1_CLASS_STRUCTURED)) || ++ (tag != strtoul ((char *) p->value, NULL, 10))) ++ return ASN1_TAG_ERROR; ++ } ++ else ++ { /* ASN1_TAG_IMPLICIT */ ++ if ((class != class_implicit) || (tag != tag_implicit)) ++ return ASN1_TAG_ERROR; ++ } ++ is_tag_implicit = 0; ++ } ++ else ++ { /* ASN1_TAG_IMPLICIT */ ++ if (!is_tag_implicit) ++ { ++ if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) || ++ (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF) ++ || (type_field (node->type) == ASN1_ETYPE_SET) ++ || (type_field (node->type) == ASN1_ETYPE_SET_OF)) ++ class2 |= ASN1_CLASS_STRUCTURED; ++ class_implicit = class2; ++ tag_implicit = strtoul ((char *) p->value, NULL, 10); ++ is_tag_implicit = 1; ++ } ++ } ++ } ++ p = p->right; ++ } ++ } ++ ++ if (is_tag_implicit) ++ { ++ if (asn1_get_tag_der ++ (der + counter, der_len, &class, &len2, ++ &tag) != ASN1_SUCCESS) ++ return ASN1_DER_ERROR; ++ ++ DECR_LEN(der_len, len2); ++ ++ if ((class != class_implicit) || (tag != tag_implicit)) ++ { ++ if (type_field (node->type) == ASN1_ETYPE_OCTET_STRING) ++ { ++ class_implicit |= ASN1_CLASS_STRUCTURED; ++ if ((class != class_implicit) || (tag != tag_implicit)) ++ return ASN1_TAG_ERROR; ++ } ++ else ++ return ASN1_TAG_ERROR; ++ } ++ } ++ else ++ { ++ unsigned type = type_field (node->type); ++ if (type == ASN1_ETYPE_TAG) ++ { ++ *tag_len = 0; ++ if (inner_tag_len) ++ *inner_tag_len = 0; ++ return ASN1_SUCCESS; ++ } ++ ++ if (asn1_get_tag_der ++ (der + counter, der_len, &class, &len2, ++ &tag) != ASN1_SUCCESS) ++ return ASN1_DER_ERROR; ++ ++ DECR_LEN(der_len, len2); ++ ++ switch (type) ++ { ++ case ASN1_ETYPE_NULL: ++ case ASN1_ETYPE_BOOLEAN: ++ case ASN1_ETYPE_INTEGER: ++ case ASN1_ETYPE_ENUMERATED: ++ case ASN1_ETYPE_OBJECT_ID: ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ case ASN1_ETYPE_BIT_STRING: ++ case ASN1_ETYPE_SEQUENCE: ++ case ASN1_ETYPE_SEQUENCE_OF: ++ case ASN1_ETYPE_SET: ++ case ASN1_ETYPE_SET_OF: ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ case ASN1_ETYPE_UTC_TIME: ++ if ((class != _asn1_tags[type].class) ++ || (tag != _asn1_tags[type].tag)) ++ return ASN1_DER_ERROR; ++ break; ++ ++ case ASN1_ETYPE_OCTET_STRING: ++ /* OCTET STRING is handled differently to allow ++ * BER encodings (structured class). */ ++ if (((class != ASN1_CLASS_UNIVERSAL) ++ && (class != (ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED))) ++ || (tag != ASN1_TAG_OCTET_STRING)) ++ return ASN1_DER_ERROR; ++ break; ++ case ASN1_ETYPE_ANY: ++ counter -= len2; ++ break; ++ case ASN1_ETYPE_CHOICE: ++ counter -= len2; ++ break; ++ default: ++ return ASN1_DER_ERROR; ++ break; ++ } ++ } ++ ++ counter += len2; ++ *tag_len = counter; ++ if (inner_tag_len) ++ *inner_tag_len = len2; ++ return ASN1_SUCCESS; ++ ++cleanup: ++ return result; ++} ++ ++static int ++extract_tag_der_recursive(asn1_node node, const unsigned char *der, int der_len, ++ int *ret_len, int *inner_len, unsigned flags) ++{ ++asn1_node p; ++int ris = ASN1_DER_ERROR; ++ ++ if (type_field (node->type) == ASN1_ETYPE_CHOICE) ++ { ++ p = node->down; ++ while (p) ++ { ++ ris = _asn1_extract_tag_der (p, der, der_len, ret_len, inner_len, flags); ++ if (ris == ASN1_SUCCESS) ++ break; ++ p = p->right; ++ } ++ ++ *ret_len = 0; ++ return ris; ++ } ++ else ++ return _asn1_extract_tag_der (node, der, der_len, ret_len, inner_len, flags); ++} ++ ++static int ++_asn1_delete_not_used (asn1_node node) ++{ ++ asn1_node p, p2; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ while (p) ++ { ++ if (p->type & CONST_NOT_USED) ++ { ++ p2 = NULL; ++ if (p != node) ++ { ++ p2 = _asn1_find_left (p); ++ if (!p2) ++ p2 = _asn1_find_up (p); ++ } ++ asn1_delete_structure (&p); ++ p = p2; ++ } ++ ++ if (!p) ++ break; /* reach node */ ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else ++ { ++ if (p == node) ++ p = NULL; ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == node) ++ { ++ p = NULL; ++ break; ++ } ++ if (p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ } ++ return ASN1_SUCCESS; ++} ++ ++static int ++_asn1_get_indefinite_length_string (const unsigned char *der, ++ int der_len, int *len) ++{ ++ int len2, len3, counter, indefinite; ++ int result; ++ unsigned long tag; ++ unsigned char class; ++ ++ counter = indefinite = 0; ++ ++ while (1) ++ { ++ if (HAVE_TWO(der_len) && (der[counter] == 0) && (der[counter + 1] == 0)) ++ { ++ counter += 2; ++ DECR_LEN(der_len, 2); ++ ++ indefinite--; ++ if (indefinite <= 0) ++ break; ++ else ++ continue; ++ } ++ ++ if (asn1_get_tag_der ++ (der + counter, der_len, &class, &len2, ++ &tag) != ASN1_SUCCESS) ++ return ASN1_DER_ERROR; ++ ++ DECR_LEN(der_len, len2); ++ counter += len2; ++ ++ len2 = asn1_get_length_der (der + counter, der_len, &len3); ++ if (len2 < -1) ++ return ASN1_DER_ERROR; ++ ++ if (len2 == -1) ++ { ++ indefinite++; ++ counter += 1; ++ DECR_LEN(der_len, 1); ++ } ++ else ++ { ++ counter += len2 + len3; ++ DECR_LEN(der_len, len2+len3); ++ } ++ } ++ ++ *len = counter; ++ return ASN1_SUCCESS; ++ ++cleanup: ++ return result; ++} ++ ++static void delete_unneeded_choice_fields(asn1_node p) ++{ ++ asn1_node p2; ++ ++ while (p->right) ++ { ++ p2 = p->right; ++ asn1_delete_structure (&p2); ++ } ++} ++ ++ ++/** ++ * asn1_der_decoding2 ++ * @element: pointer to an ASN1 structure. ++ * @ider: vector that contains the DER encoding. ++ * @max_ider_len: pointer to an integer giving the information about the ++ * maximal number of bytes occupied by *@ider. The real size of the DER ++ * encoding is returned through this pointer. ++ * @flags: flags controlling the behaviour of the function. ++ * @errorDescription: null-terminated string contains details when an ++ * error occurred. ++ * ++ * Fill the structure *@element with values of a DER encoding string. The ++ * structure must just be created with function asn1_create_element(). ++ * ++ * If %ASN1_DECODE_FLAG_ALLOW_PADDING flag is set then the function will ignore ++ * padding after the decoded DER data. Upon a successful return the value of ++ * *@max_ider_len will be set to the number of bytes decoded. ++ * ++ * If %ASN1_DECODE_FLAG_STRICT_DER flag is set then the function will ++ * not decode any BER-encoded elements. ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND ++ * if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or ++ * %ASN1_DER_ERROR if the der encoding doesn't match the structure ++ * name (*@ELEMENT deleted). ++ **/ ++int ++asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, ++ unsigned int flags, char *errorDescription) ++{ ++ asn1_node node, p, p2, p3; ++ char temp[128]; ++ int counter, len2, len3, len4, move, ris, tlen; ++ struct node_tail_cache_st tcache = {NULL, NULL}; ++ unsigned char class; ++ unsigned long tag; ++ int tag_len; ++ int indefinite, result, total_len = *max_ider_len, ider_len = *max_ider_len; ++ int inner_tag_len; ++ unsigned char *ptmp; ++ const unsigned char *ptag; ++ const unsigned char *der = ider; ++ ++ node = *element; ++ ++ if (errorDescription != NULL) ++ errorDescription[0] = 0; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ if (node->type & CONST_OPTION) ++ { ++ result = ASN1_GENERIC_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ counter = 0; ++ move = DOWN; ++ p = node; ++ while (1) ++ { ++ tag_len = 0; ++ inner_tag_len = 0; ++ ris = ASN1_SUCCESS; ++ if (move != UP) ++ { ++ if (p->type & CONST_SET) ++ { ++ p2 = _asn1_find_up (p); ++ len2 = p2->tmp_ival; ++ if (len2 == -1) ++ { ++ if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1]) ++ { ++ p = p2; ++ move = UP; ++ counter += 2; ++ DECR_LEN(ider_len, 2); ++ continue; ++ } ++ } ++ else if (counter == len2) ++ { ++ p = p2; ++ move = UP; ++ continue; ++ } ++ else if (counter > len2) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ p2 = p2->down; ++ while (p2) ++ { ++ if ((p2->type & CONST_SET) && (p2->type & CONST_NOT_USED)) ++ { ++ ris = ++ extract_tag_der_recursive (p2, der + counter, ++ ider_len, &len2, NULL, flags); ++ if (ris == ASN1_SUCCESS) ++ { ++ p2->type &= ~CONST_NOT_USED; ++ p = p2; ++ break; ++ } ++ } ++ p2 = p2->right; ++ } ++ if (p2 == NULL) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ } ++ ++ /* the position in the DER structure this starts */ ++ p->start = counter; ++ p->end = total_len - 1; ++ ++ if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT)) ++ { ++ p2 = _asn1_find_up (p); ++ len2 = p2->tmp_ival; ++ if (counter == len2) ++ { ++ if (p->right) ++ { ++ p2 = p->right; ++ move = RIGHT; ++ } ++ else ++ move = UP; ++ ++ if (p->type & CONST_OPTION) ++ asn1_delete_structure (&p); ++ ++ p = p2; ++ continue; ++ } ++ } ++ ++ if (type_field (p->type) == ASN1_ETYPE_CHOICE) ++ { ++ while (p->down) ++ { ++ ris = ++ extract_tag_der_recursive (p->down, der + counter, ++ ider_len, &len2, NULL, flags); ++ ++ if (ris == ASN1_SUCCESS) ++ { ++ delete_unneeded_choice_fields(p->down); ++ break; ++ } ++ else if (ris == ASN1_ERROR_TYPE_ANY) ++ { ++ result = ASN1_ERROR_TYPE_ANY; ++ warn(); ++ goto cleanup; ++ } ++ else ++ { ++ p2 = p->down; ++ asn1_delete_structure (&p2); ++ } ++ } ++ ++ if (p->down == NULL) ++ { ++ if (!(p->type & CONST_OPTION)) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ } ++ else if (type_field (p->type) != ASN1_ETYPE_CHOICE) ++ p = p->down; ++ ++ p->start = counter; ++ } ++ ++ if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT)) ++ { ++ p2 = _asn1_find_up (p); ++ len2 = p2->tmp_ival; ++ ++ if ((len2 != -1) && (counter > len2)) ++ ris = ASN1_TAG_ERROR; ++ } ++ ++ if (ris == ASN1_SUCCESS) ++ ris = ++ extract_tag_der_recursive (p, der + counter, ider_len, ++ &tag_len, &inner_tag_len, flags); ++ ++ if (ris != ASN1_SUCCESS) ++ { ++ if (p->type & CONST_OPTION) ++ { ++ p->type |= CONST_NOT_USED; ++ move = RIGHT; ++ } ++ else if (p->type & CONST_DEFAULT) ++ { ++ _asn1_set_value (p, NULL, 0); ++ move = RIGHT; ++ } ++ else ++ { ++ if (errorDescription != NULL) ++ _asn1_error_description_tag_error (p, errorDescription); ++ ++ result = ASN1_TAG_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ } ++ else ++ { ++ DECR_LEN(ider_len, tag_len); ++ counter += tag_len; ++ } ++ } ++ ++ if (ris == ASN1_SUCCESS) ++ { ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_NULL: ++ DECR_LEN(ider_len, 1); ++ if (der[counter]) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ counter++; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_BOOLEAN: ++ DECR_LEN(ider_len, 2); ++ ++ if (der[counter++] != 1) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ if (der[counter++] == 0) ++ _asn1_set_value (p, "F", 1); ++ else ++ _asn1_set_value (p, "T", 1); ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_INTEGER: ++ case ASN1_ETYPE_ENUMERATED: ++ len2 = ++ asn1_get_length_der (der + counter, ider_len, &len3); ++ if (len2 < 0) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len3+len2); ++ ++ _asn1_set_value (p, der + counter, len3 + len2); ++ counter += len3 + len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_OBJECT_ID: ++ result = ++ asn1_get_object_id_der (der + counter, ider_len, &len2, ++ temp, sizeof (temp)); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len2); ++ ++ tlen = strlen (temp); ++ if (tlen > 0) ++ _asn1_set_value (p, temp, tlen + 1); ++ ++ counter += len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ case ASN1_ETYPE_UTC_TIME: ++ result = ++ _asn1_get_time_der (type_field (p->type), der + counter, ider_len, &len2, temp, ++ sizeof (temp) - 1, flags); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len2); ++ ++ tlen = strlen (temp); ++ if (tlen > 0) ++ _asn1_set_value (p, temp, tlen); ++ ++ counter += len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_OCTET_STRING: ++ if (counter < inner_tag_len) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ ptag = der + counter - inner_tag_len; ++ if ((flags & ASN1_DECODE_FLAG_STRICT_DER) || !(ptag[0] & ASN1_CLASS_STRUCTURED)) ++ { ++ if (ptag[0] & ASN1_CLASS_STRUCTURED) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ len2 = ++ asn1_get_length_der (der + counter, ider_len, &len3); ++ if (len2 < 0) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len3+len2); ++ ++ _asn1_set_value (p, der + counter, len3 + len2); ++ counter += len3 + len2; ++ } ++ else ++ { ++ unsigned dflags = 0, vlen, ber_len; ++ ++ if (ptag[0] & ASN1_CLASS_STRUCTURED) ++ dflags |= DECODE_FLAG_CONSTRUCTED; ++ ++ result = _asn1_decode_simple_ber(type_field (p->type), der+counter, ider_len, &ptmp, &vlen, &ber_len, dflags); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, ber_len); ++ ++ _asn1_set_value_lv (p, ptmp, vlen); ++ ++ counter += ber_len; ++ free(ptmp); ++ } ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ case ASN1_ETYPE_BIT_STRING: ++ len2 = ++ asn1_get_length_der (der + counter, ider_len, &len3); ++ if (len2 < 0) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len3+len2); ++ ++ _asn1_set_value (p, der + counter, len3 + len2); ++ counter += len3 + len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_SEQUENCE: ++ case ASN1_ETYPE_SET: ++ if (move == UP) ++ { ++ len2 = p->tmp_ival; ++ p->tmp_ival = 0; ++ if (len2 == -1) ++ { /* indefinite length method */ ++ DECR_LEN(ider_len, 2); ++ if ((der[counter]) || der[counter + 1]) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ counter += 2; ++ } ++ else ++ { /* definite length method */ ++ if (len2 != counter) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ } ++ move = RIGHT; ++ } ++ else ++ { /* move==DOWN || move==RIGHT */ ++ len3 = ++ asn1_get_length_der (der + counter, ider_len, &len2); ++ if (IS_ERR(len3, flags)) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len2); ++ counter += len2; ++ ++ if (len3 > 0) ++ { ++ p->tmp_ival = counter + len3; ++ move = DOWN; ++ } ++ else if (len3 == 0) ++ { ++ p2 = p->down; ++ while (p2) ++ { ++ if (type_field (p2->type) != ASN1_ETYPE_TAG) ++ { ++ p3 = p2->right; ++ asn1_delete_structure (&p2); ++ p2 = p3; ++ } ++ else ++ p2 = p2->right; ++ } ++ move = RIGHT; ++ } ++ else ++ { /* indefinite length method */ ++ p->tmp_ival = -1; ++ move = DOWN; ++ } ++ } ++ break; ++ case ASN1_ETYPE_SEQUENCE_OF: ++ case ASN1_ETYPE_SET_OF: ++ if (move == UP) ++ { ++ len2 = p->tmp_ival; ++ if (len2 == -1) ++ { /* indefinite length method */ ++ if (!HAVE_TWO(ider_len) || ((der[counter]) || der[counter + 1])) ++ { ++ result = _asn1_append_sequence_set (p, &tcache); ++ if (result != 0) ++ { ++ warn(); ++ goto cleanup; ++ } ++ p = tcache.tail; ++ move = RIGHT; ++ continue; ++ } ++ ++ p->tmp_ival = 0; ++ tcache.tail = NULL; /* finished decoding this structure */ ++ tcache.head = NULL; ++ DECR_LEN(ider_len, 2); ++ counter += 2; ++ } ++ else ++ { /* definite length method */ ++ if (len2 > counter) ++ { ++ result = _asn1_append_sequence_set (p, &tcache); ++ if (result != 0) ++ { ++ warn(); ++ goto cleanup; ++ } ++ p = tcache.tail; ++ move = RIGHT; ++ continue; ++ } ++ ++ p->tmp_ival = 0; ++ tcache.tail = NULL; /* finished decoding this structure */ ++ tcache.head = NULL; ++ ++ if (len2 != counter) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ } ++ } ++ else ++ { /* move==DOWN || move==RIGHT */ ++ len3 = ++ asn1_get_length_der (der + counter, ider_len, &len2); ++ if (IS_ERR(len3, flags)) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len2); ++ counter += len2; ++ if (len3) ++ { ++ if (len3 > 0) ++ { /* definite length method */ ++ p->tmp_ival = counter + len3; ++ } ++ else ++ { /* indefinite length method */ ++ p->tmp_ival = -1; ++ } ++ ++ p2 = p->down; ++ if (p2 == NULL) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ while ((type_field (p2->type) == ASN1_ETYPE_TAG) ++ || (type_field (p2->type) == ASN1_ETYPE_SIZE)) ++ p2 = p2->right; ++ if (p2->right == NULL) ++ { ++ result = _asn1_append_sequence_set (p, &tcache); ++ if (result != 0) ++ { ++ warn(); ++ goto cleanup; ++ } ++ } ++ p = p2; ++ } ++ } ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_ANY: ++ /* Check indefinite lenth method in an EXPLICIT TAG */ ++ ++ if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) && (p->type & CONST_TAG) && ++ tag_len == 2 && (der[counter - 1] == 0x80)) ++ indefinite = 1; ++ else ++ indefinite = 0; ++ ++ if (asn1_get_tag_der ++ (der + counter, ider_len, &class, &len2, ++ &tag) != ASN1_SUCCESS) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len2); ++ ++ len4 = ++ asn1_get_length_der (der + counter + len2, ++ ider_len, &len3); ++ if (IS_ERR(len4, flags)) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ if (len4 != -1) /* definite */ ++ { ++ len2 += len4; ++ ++ DECR_LEN(ider_len, len4+len3); ++ _asn1_set_value_lv (p, der + counter, len2 + len3); ++ counter += len2 + len3; ++ } ++ else /* == -1 */ ++ { /* indefinite length */ ++ ider_len += len2; /* undo DECR_LEN */ ++ ++ if (counter == 0) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ result = ++ _asn1_get_indefinite_length_string (der + counter, ider_len, &len2); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len2); ++ _asn1_set_value_lv (p, der + counter, len2); ++ counter += len2; ++ ++ } ++ ++ /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with ++ an indefinite length method. */ ++ if (indefinite) ++ { ++ DECR_LEN(ider_len, 2); ++ if (!der[counter] && !der[counter + 1]) ++ { ++ counter += 2; ++ } ++ else ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ } ++ ++ move = RIGHT; ++ break; ++ default: ++ move = (move == UP) ? RIGHT : DOWN; ++ break; ++ } ++ } ++ ++ if (p) ++ { ++ p->end = counter - 1; ++ } ++ ++ if (p == node && move != DOWN) ++ break; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ if ((move == RIGHT) && !(p->type & CONST_SET)) ++ { ++ if (p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ _asn1_delete_not_used (*element); ++ ++ if ((ider_len < 0) || ++ (!(flags & ASN1_DECODE_FLAG_ALLOW_PADDING) && (ider_len != 0))) ++ { ++ warn(); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ ++ *max_ider_len = total_len - ider_len; ++ ++ return ASN1_SUCCESS; ++ ++cleanup: ++ asn1_delete_structure (element); ++ return result; ++} ++ ++ ++/** ++ * asn1_der_decoding: ++ * @element: pointer to an ASN1 structure. ++ * @ider: vector that contains the DER encoding. ++ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1]. ++ * @errorDescription: null-terminated string contains details when an ++ * error occurred. ++ * ++ * Fill the structure *@element with values of a DER encoding ++ * string. The structure must just be created with function ++ * asn1_create_element(). ++ * ++ * Note that the *@element variable is provided as a pointer for ++ * historical reasons. ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND ++ * if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or ++ * %ASN1_DER_ERROR if the der encoding doesn't match the structure ++ * name (*@ELEMENT deleted). ++ **/ ++int ++asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, ++ char *errorDescription) ++{ ++ return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription); ++} ++ ++#if 0 ++/** ++ * asn1_der_decoding_element: ++ * @structure: pointer to an ASN1 structure ++ * @elementName: name of the element to fill ++ * @ider: vector that contains the DER encoding of the whole structure. ++ * @len: number of bytes of *der: der[0]..der[len-1] ++ * @errorDescription: null-terminated string contains details when an ++ * error occurred. ++ * ++ * Fill the element named @ELEMENTNAME with values of a DER encoding ++ * string. The structure must just be created with function ++ * asn1_create_element(). The DER vector must contain the encoding ++ * string of the whole @STRUCTURE. If an error occurs during the ++ * decoding procedure, the *@STRUCTURE is deleted and set equal to ++ * %NULL. ++ * ++ * This function is deprecated and may just be an alias to asn1_der_decoding ++ * in future versions. Use asn1_der_decoding() instead. ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND ++ * if ELEMENT is %NULL or @elementName == NULL, and ++ * %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding doesn't ++ * match the structure @structure (*ELEMENT deleted). ++ **/ ++int ++asn1_der_decoding_element (asn1_node * structure, const char *elementName, ++ const void *ider, int len, char *errorDescription) ++{ ++ return asn1_der_decoding(structure, ider, len, errorDescription); ++} ++#endif ++ ++/** ++ * asn1_der_decoding_startEnd: ++ * @element: pointer to an ASN1 element ++ * @ider: vector that contains the DER encoding. ++ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1] ++ * @name_element: an element of NAME structure. ++ * @start: the position of the first byte of NAME_ELEMENT decoding ++ * (@ider[*start]) ++ * @end: the position of the last byte of NAME_ELEMENT decoding ++ * (@ider[*end]) ++ * ++ * Find the start and end point of an element in a DER encoding ++ * string. I mean that if you have a der encoding and you have already ++ * used the function asn1_der_decoding() to fill a structure, it may ++ * happen that you want to find the piece of string concerning an ++ * element of the structure. ++ * ++ * One example is the sequence "tbsCertificate" inside an X509 ++ * certificate. ++ * ++ * Note that since libtasn1 3.7 the @ider and @ider_len parameters ++ * can be omitted, if the element is already decoded using asn1_der_decoding(). ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND ++ * if ELEMENT is %asn1_node EMPTY or @name_element is not a valid ++ * element, %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding ++ * doesn't match the structure ELEMENT. ++ **/ ++int ++asn1_der_decoding_startEnd (asn1_node element, const void *ider, int ider_len, ++ const char *name_element, int *start, int *end) ++{ ++ asn1_node node, node_to_find; ++ int result = ASN1_DER_ERROR; ++ ++ node = element; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ node_to_find = asn1_find_node (node, name_element); ++ ++ if (node_to_find == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ *start = node_to_find->start; ++ *end = node_to_find->end; ++ ++ if (*start == 0 && *end == 0) ++ { ++ if (ider == NULL || ider_len == 0) ++ return ASN1_GENERIC_ERROR; ++ ++ /* it seems asn1_der_decoding() wasn't called before. Do it now */ ++ result = asn1_der_decoding (&node, ider, ider_len, NULL); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ return result; ++ } ++ ++ node_to_find = asn1_find_node (node, name_element); ++ if (node_to_find == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ *start = node_to_find->start; ++ *end = node_to_find->end; ++ } ++ ++ if (*end < *start) ++ return ASN1_GENERIC_ERROR; ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_expand_any_defined_by: ++ * @definitions: ASN1 definitions ++ * @element: pointer to an ASN1 structure ++ * ++ * Expands every "ANY DEFINED BY" element of a structure created from ++ * a DER decoding process (asn1_der_decoding function). The element ++ * ANY must be defined by an OBJECT IDENTIFIER. The type used to ++ * expand the element ANY is the first one following the definition of ++ * the actual value of the OBJECT IDENTIFIER. ++ * ++ * Returns: %ASN1_SUCCESS if Substitution OK, %ASN1_ERROR_TYPE_ANY if ++ * some "ANY DEFINED BY" element couldn't be expanded due to a ++ * problem in OBJECT_ID -> TYPE association, or other error codes ++ * depending on DER decoding. ++ **/ ++int ++asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element) ++{ ++ char name[2 * ASN1_MAX_NAME_SIZE + 2], ++ value[ASN1_MAX_NAME_SIZE]; ++ int retCode = ASN1_SUCCESS, result; ++ int len, len2, len3; ++ asn1_node_const p2; ++ asn1_node p, p3, aux = NULL; ++ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ const char *definitionsName; ++ ++ if ((definitions == NULL) || (*element == NULL)) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ definitionsName = definitions->name; ++ ++ p = *element; ++ while (p) ++ { ++ ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_ANY: ++ if ((p->type & CONST_DEFINED_BY) && (p->value)) ++ { ++ /* search the "DEF_BY" element */ ++ p2 = p->down; ++ while ((p2) && (type_field (p2->type) != ASN1_ETYPE_CONSTANT)) ++ p2 = p2->right; ++ ++ if (!p2) ++ { ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ ++ p3 = _asn1_find_up (p); ++ ++ if (!p3) ++ { ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ ++ p3 = p3->down; ++ while (p3) ++ { ++ if (!(strcmp (p3->name, p2->name))) ++ break; ++ p3 = p3->right; ++ } ++ ++ if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) || ++ (p3->value == NULL)) ++ { ++ ++ p3 = _asn1_find_up (p); ++ p3 = _asn1_find_up (p3); ++ ++ if (!p3) ++ { ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ ++ p3 = p3->down; ++ ++ while (p3) ++ { ++ if (!(strcmp (p3->name, p2->name))) ++ break; ++ p3 = p3->right; ++ } ++ ++ if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ++ || (p3->value == NULL)) ++ { ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ } ++ ++ /* search the OBJECT_ID into definitions */ ++ p2 = definitions->down; ++ while (p2) ++ { ++ if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p2->type & CONST_ASSIGN)) ++ { ++ snprintf(name, sizeof(name), "%s.%s", definitionsName, p2->name); ++ ++ len = ASN1_MAX_NAME_SIZE; ++ result = ++ asn1_read_value (definitions, name, value, &len); ++ ++ if ((result == ASN1_SUCCESS) ++ && (!_asn1_strcmp (p3->value, value))) ++ { ++ p2 = p2->right; /* pointer to the structure to ++ use for expansion */ ++ while ((p2) && (p2->type & CONST_ASSIGN)) ++ p2 = p2->right; ++ ++ if (p2) ++ { ++ snprintf(name, sizeof(name), "%s.%s", definitionsName, p2->name); ++ ++ result = ++ asn1_create_element (definitions, name, &aux); ++ if (result == ASN1_SUCCESS) ++ { ++ _asn1_cpy_name (aux, p); ++ len2 = ++ asn1_get_length_der (p->value, ++ p->value_len, &len3); ++ if (len2 < 0) ++ return ASN1_DER_ERROR; ++ ++ result = ++ asn1_der_decoding (&aux, p->value + len3, ++ len2, ++ errorDescription); ++ if (result == ASN1_SUCCESS) ++ { ++ ++ _asn1_set_right (aux, p->right); ++ _asn1_set_right (p, aux); ++ ++ result = asn1_delete_structure (&p); ++ if (result == ASN1_SUCCESS) ++ { ++ p = aux; ++ aux = NULL; ++ break; ++ } ++ else ++ { /* error with asn1_delete_structure */ ++ asn1_delete_structure (&aux); ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with asn1_der_decoding */ ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with asn1_create_element */ ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with the pointer to the structure to exapand */ ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ } ++ } ++ p2 = p2->right; ++ } /* end while */ ++ ++ if (!p2) ++ { ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ ++ } ++ break; ++ default: ++ break; ++ } ++ ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else if (p == *element) ++ { ++ p = NULL; ++ break; ++ } ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == *element) ++ { ++ p = NULL; ++ break; ++ } ++ if (p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ ++ return retCode; ++} ++ ++/** ++ * asn1_expand_octet_string: ++ * @definitions: ASN1 definitions ++ * @element: pointer to an ASN1 structure ++ * @octetName: name of the OCTECT STRING field to expand. ++ * @objectName: name of the OBJECT IDENTIFIER field to use to define ++ * the type for expansion. ++ * ++ * Expands an "OCTET STRING" element of a structure created from a DER ++ * decoding process (the asn1_der_decoding() function). The type used ++ * for expansion is the first one following the definition of the ++ * actual value of the OBJECT IDENTIFIER indicated by OBJECTNAME. ++ * ++ * Returns: %ASN1_SUCCESS if substitution OK, %ASN1_ELEMENT_NOT_FOUND ++ * if @objectName or @octetName are not correct, ++ * %ASN1_VALUE_NOT_VALID if it wasn't possible to find the type to ++ * use for expansion, or other errors depending on DER decoding. ++ **/ ++int ++asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element, ++ const char *octetName, const char *objectName) ++{ ++ char name[2 * ASN1_MAX_NAME_SIZE + 1], value[ASN1_MAX_NAME_SIZE]; ++ int retCode = ASN1_SUCCESS, result; ++ int len, len2, len3; ++ asn1_node_const p2; ++ asn1_node aux = NULL; ++ asn1_node octetNode = NULL, objectNode = NULL; ++ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ ++ if ((definitions == NULL) || (*element == NULL)) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ octetNode = asn1_find_node (*element, octetName); ++ if (octetNode == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ if (type_field (octetNode->type) != ASN1_ETYPE_OCTET_STRING) ++ return ASN1_ELEMENT_NOT_FOUND; ++ if (octetNode->value == NULL) ++ return ASN1_VALUE_NOT_FOUND; ++ ++ objectNode = asn1_find_node (*element, objectName); ++ if (objectNode == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ if (type_field (objectNode->type) != ASN1_ETYPE_OBJECT_ID) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ if (objectNode->value == NULL) ++ return ASN1_VALUE_NOT_FOUND; ++ ++ ++ /* search the OBJECT_ID into definitions */ ++ p2 = definitions->down; ++ while (p2) ++ { ++ if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p2->type & CONST_ASSIGN)) ++ { ++ strcpy (name, definitions->name); ++ memcpy (name + strlen(name), ".", sizeof(" . ")); ++ memcpy (name + strlen(name), p2->name, strlen(p2->name) + 1); ++ ++ len = sizeof (value); ++ result = asn1_read_value (definitions, name, value, &len); ++ ++ if ((result == ASN1_SUCCESS) ++ && (!_asn1_strcmp (objectNode->value, value))) ++ { ++ ++ p2 = p2->right; /* pointer to the structure to ++ use for expansion */ ++ while ((p2) && (p2->type & CONST_ASSIGN)) ++ p2 = p2->right; ++ ++ if (p2) ++ { ++ strcpy (name, definitions->name); ++ memcpy (name + strlen(name), ".", sizeof(" . ")); ++ memcpy (name + strlen(name), p2->name, strlen(p2->name) + 1); ++ ++ result = asn1_create_element (definitions, name, &aux); ++ if (result == ASN1_SUCCESS) ++ { ++ _asn1_cpy_name (aux, octetNode); ++ len2 = ++ asn1_get_length_der (octetNode->value, ++ octetNode->value_len, &len3); ++ if (len2 < 0) ++ return ASN1_DER_ERROR; ++ ++ result = ++ asn1_der_decoding (&aux, octetNode->value + len3, ++ len2, errorDescription); ++ if (result == ASN1_SUCCESS) ++ { ++ ++ _asn1_set_right (aux, octetNode->right); ++ _asn1_set_right (octetNode, aux); ++ ++ result = asn1_delete_structure (&octetNode); ++ if (result == ASN1_SUCCESS) ++ { ++ aux = NULL; ++ break; ++ } ++ else ++ { /* error with asn1_delete_structure */ ++ asn1_delete_structure (&aux); ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with asn1_der_decoding */ ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with asn1_create_element */ ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with the pointer to the structure to exapand */ ++ retCode = ASN1_VALUE_NOT_VALID; ++ break; ++ } ++ } ++ } ++ ++ p2 = p2->right; ++ ++ } ++ ++ if (!p2) ++ retCode = ASN1_VALUE_NOT_VALID; ++ ++ return retCode; ++} ++ ++/*- ++ * _asn1_decode_simple_der: ++ * @etype: The type of the string to be encoded (ASN1_ETYPE_) ++ * @der: the encoded string ++ * @_der_len: the bytes of the encoded string ++ * @str: a pointer to the data ++ * @str_len: the length of the data ++ * @dflags: DECODE_FLAG_* ++ * ++ * Decodes a simple DER encoded type (e.g. a string, which is not constructed). ++ * The output is a pointer inside the @der. ++ * ++ * Returns: %ASN1_SUCCESS if successful or an error value. ++ -*/ ++static int ++_asn1_decode_simple_der (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, const unsigned char **str, ++ unsigned int *str_len, unsigned dflags) ++{ ++ int tag_len, len_len; ++ const unsigned char *p; ++ int der_len = _der_len; ++ unsigned char class; ++ unsigned long tag; ++ long ret; ++ ++ if (der == NULL || der_len == 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ if (ETYPE_OK (etype) == 0 || ETYPE_IS_STRING(etype) == 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ /* doesn't handle constructed classes */ ++ class = ETYPE_CLASS(etype); ++ if (class != ASN1_CLASS_UNIVERSAL) ++ return ASN1_VALUE_NOT_VALID; ++ ++ p = der; ++ ++ if (dflags & DECODE_FLAG_HAVE_TAG) ++ { ++ ret = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag); ++ if (ret != ASN1_SUCCESS) ++ return ret; ++ ++ if (class != ETYPE_CLASS (etype) || tag != ETYPE_TAG (etype)) ++ { ++ warn(); ++ return ASN1_DER_ERROR; ++ } ++ ++ p += tag_len; ++ der_len -= tag_len; ++ if (der_len <= 0) ++ return ASN1_DER_ERROR; ++ } ++ ++ ret = asn1_get_length_der (p, der_len, &len_len); ++ if (ret < 0) ++ return ASN1_DER_ERROR; ++ ++ p += len_len; ++ der_len -= len_len; ++ if (der_len <= 0) ++ return ASN1_DER_ERROR; ++ ++ *str_len = ret; ++ *str = p; ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_decode_simple_der: ++ * @etype: The type of the string to be encoded (ASN1_ETYPE_) ++ * @der: the encoded string ++ * @_der_len: the bytes of the encoded string ++ * @str: a pointer to the data ++ * @str_len: the length of the data ++ * ++ * Decodes a simple DER encoded type (e.g. a string, which is not constructed). ++ * The output is a pointer inside the @der. ++ * ++ * Returns: %ASN1_SUCCESS if successful or an error value. ++ **/ ++int ++asn1_decode_simple_der (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, const unsigned char **str, ++ unsigned int *str_len) ++{ ++ return _asn1_decode_simple_der(etype, der, _der_len, str, str_len, DECODE_FLAG_HAVE_TAG); ++} ++ ++static int append(uint8_t **dst, unsigned *dst_size, const unsigned char *src, unsigned src_size) ++{ ++ if (src_size == 0) ++ return ASN1_SUCCESS; ++ ++ *dst = _asn1_realloc(*dst, *dst_size+src_size); ++ if (*dst == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ memcpy(*dst + *dst_size, src, src_size); ++ *dst_size += src_size; ++ return ASN1_SUCCESS; ++} ++ ++/*- ++ * _asn1_decode_simple_ber: ++ * @etype: The type of the string to be encoded (ASN1_ETYPE_) ++ * @der: the encoded string ++ * @_der_len: the bytes of the encoded string ++ * @str: a pointer to the data ++ * @str_len: the length of the data ++ * @ber_len: the total length occupied by BER (may be %NULL) ++ * @have_tag: whether a DER tag is included ++ * ++ * Decodes a BER encoded type. The output is an allocated value ++ * of the data. This decodes BER STRINGS only. Other types are ++ * decoded as DER. ++ * ++ * Returns: %ASN1_SUCCESS if successful or an error value. ++ -*/ ++static int ++_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, unsigned char **str, ++ unsigned int *str_len, unsigned int *ber_len, ++ unsigned dflags) ++{ ++ int tag_len, len_len; ++ const unsigned char *p; ++ int der_len = _der_len; ++ uint8_t *total = NULL; ++ unsigned total_size = 0; ++ unsigned char class; ++ unsigned long tag; ++ unsigned char *out = NULL; ++ const unsigned char *cout = NULL; ++ unsigned out_len; ++ long result; ++ ++ if (ber_len) *ber_len = 0; ++ ++ if (der == NULL || der_len == 0) ++ { ++ warn(); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ if (ETYPE_OK (etype) == 0) ++ { ++ warn(); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ /* doesn't handle constructed + definite classes */ ++ class = ETYPE_CLASS (etype); ++ if (class != ASN1_CLASS_UNIVERSAL) ++ { ++ warn(); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ p = der; ++ ++ if (dflags & DECODE_FLAG_HAVE_TAG) ++ { ++ result = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ return result; ++ } ++ ++ if (tag != ETYPE_TAG (etype)) ++ { ++ warn(); ++ return ASN1_DER_ERROR; ++ } ++ ++ p += tag_len; ++ ++ DECR_LEN(der_len, tag_len); ++ ++ if (ber_len) *ber_len += tag_len; ++ } ++ ++ /* indefinite constructed */ ++ if ((((dflags & DECODE_FLAG_CONSTRUCTED) || class == ASN1_CLASS_STRUCTURED) && ETYPE_IS_STRING(etype)) && ++ !(dflags & DECODE_FLAG_LEVEL3)) ++ { ++ if (der_len == 0) ++ { ++ warn(); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ ++ if (der_len > 0 && p[0] == 0x80) /* indefinite */ ++ { ++ len_len = 1; ++ DECR_LEN(der_len, len_len); ++ p += len_len; ++ ++ if (ber_len) *ber_len += len_len; ++ ++ /* decode the available octet strings */ ++ do ++ { ++ unsigned tmp_len; ++ unsigned flags = DECODE_FLAG_HAVE_TAG; ++ ++ if (dflags & DECODE_FLAG_LEVEL1) ++ flags |= DECODE_FLAG_LEVEL2; ++ else if (dflags & DECODE_FLAG_LEVEL2) ++ flags |= DECODE_FLAG_LEVEL3; ++ else ++ flags |= DECODE_FLAG_LEVEL1; ++ ++ result = _asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len, ++ flags); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ p += tmp_len; ++ DECR_LEN(der_len, tmp_len); ++ ++ if (ber_len) *ber_len += tmp_len; ++ ++ DECR_LEN(der_len, 2); /* we need the EOC */ ++ ++ result = append(&total, &total_size, out, out_len); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ free(out); ++ out = NULL; ++ ++ if (p[0] == 0 && p[1] == 0) /* EOC */ ++ { ++ if (ber_len) *ber_len += 2; ++ break; ++ } ++ ++ /* no EOC */ ++ der_len += 2; ++ ++ if (der_len == 2) ++ { ++ warn(); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ } ++ while(1); ++ } ++ else /* constructed */ ++ { ++ long const_len; ++ ++ result = asn1_get_length_ber(p, der_len, &len_len); ++ if (result < 0) ++ { ++ warn(); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ ++ DECR_LEN(der_len, len_len); ++ p += len_len; ++ ++ const_len = result; ++ ++ if (ber_len) *ber_len += len_len; ++ ++ /* decode the available octet strings */ ++ while(const_len > 0) ++ { ++ unsigned tmp_len; ++ unsigned flags = DECODE_FLAG_HAVE_TAG; ++ ++ if (dflags & DECODE_FLAG_LEVEL1) ++ flags |= DECODE_FLAG_LEVEL2; ++ else if (dflags & DECODE_FLAG_LEVEL2) ++ flags |= DECODE_FLAG_LEVEL3; ++ else ++ flags |= DECODE_FLAG_LEVEL1; ++ ++ result = _asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len, ++ flags); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ p += tmp_len; ++ DECR_LEN(der_len, tmp_len); ++ DECR_LEN(const_len, tmp_len); ++ ++ if (ber_len) *ber_len += tmp_len; ++ ++ result = append(&total, &total_size, out, out_len); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ free(out); ++ out = NULL; ++ } ++ } ++ } ++ else if (class == ETYPE_CLASS(etype)) ++ { ++ if (ber_len) ++ { ++ result = asn1_get_length_der (p, der_len, &len_len); ++ if (result < 0) ++ { ++ warn(); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ *ber_len += result + len_len; ++ } ++ ++ /* non-string values are decoded as DER */ ++ result = _asn1_decode_simple_der(etype, der, _der_len, &cout, &out_len, dflags); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ result = append(&total, &total_size, cout, out_len); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ } ++ else ++ { ++ warn(); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ ++ *str = total; ++ *str_len = total_size; ++ ++ return ASN1_SUCCESS; ++cleanup: ++ free(out); ++ free(total); ++ return result; ++} ++ ++/** ++ * asn1_decode_simple_ber: ++ * @etype: The type of the string to be encoded (ASN1_ETYPE_) ++ * @der: the encoded string ++ * @_der_len: the bytes of the encoded string ++ * @str: a pointer to the data ++ * @str_len: the length of the data ++ * @ber_len: the total length occupied by BER (may be %NULL) ++ * ++ * Decodes a BER encoded type. The output is an allocated value ++ * of the data. This decodes BER STRINGS only. Other types are ++ * decoded as DER. ++ * ++ * Returns: %ASN1_SUCCESS if successful or an error value. ++ **/ ++int ++asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, unsigned char **str, ++ unsigned int *str_len, unsigned int *ber_len) ++{ ++ return _asn1_decode_simple_ber(etype, der, _der_len, str, str_len, ber_len, DECODE_FLAG_HAVE_TAG); ++} +diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c +new file mode 100644 +index 000000000..8cc73455a +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/element.c +@@ -0,0 +1,1112 @@ ++/* ++ * Copyright (C) 2000-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++/*****************************************************/ ++/* File: element.c */ ++/* Description: Functions with the read and write */ ++/* functions. */ ++/*****************************************************/ ++ ++ ++#include ++#include "parser_aux.h" ++#include ++#include "structure.h" ++#include "element.h" ++ ++#define c_isdigit grub_isdigit ++ ++void ++_asn1_hierarchical_name (asn1_node_const node, char *name, int name_size) ++{ ++ asn1_node_const p; ++ char tmp_name[64]; ++ ++ p = node; ++ ++ name[0] = 0; ++ ++ while (p != NULL) ++ { ++ if (p->name[0] != 0) ++ { ++ _asn1_str_cpy (tmp_name, sizeof (tmp_name), name), ++ _asn1_str_cpy (name, name_size, p->name); ++ _asn1_str_cat (name, name_size, "."); ++ _asn1_str_cat (name, name_size, tmp_name); ++ } ++ p = _asn1_find_up (p); ++ } ++ ++ if (name[0] == 0) ++ _asn1_str_cpy (name, name_size, "ROOT"); ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_convert_integer */ ++/* Description: converts an integer from a null terminated string */ ++/* to der decoding. The convertion from a null */ ++/* terminated string to an integer is made with */ ++/* the 'strtol' function. */ ++/* Parameters: */ ++/* value: null terminated string to convert. */ ++/* value_out: convertion result (memory must be already */ ++/* allocated). */ ++/* value_out_size: number of bytes of value_out. */ ++/* len: number of significant byte of value_out. */ ++/* Return: ASN1_MEM_ERROR or ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_convert_integer (const unsigned char *value, unsigned char *value_out, ++ int value_out_size, int *len) ++{ ++ char negative; ++ unsigned char val[SIZEOF_UNSIGNED_LONG_INT]; ++ long valtmp; ++ int k, k2; ++ ++ valtmp = _asn1_strtol (value, NULL, 10); ++ ++ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++) ++ { ++ val[SIZEOF_UNSIGNED_LONG_INT - k - 1] = (valtmp >> (8 * k)) & 0xFF; ++ } ++ ++ if (val[0] & 0x80) ++ negative = 1; ++ else ++ negative = 0; ++ ++ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT - 1; k++) ++ { ++ if (negative && (val[k] != 0xFF)) ++ break; ++ else if (!negative && val[k]) ++ break; ++ } ++ ++ if ((negative && !(val[k] & 0x80)) || (!negative && (val[k] & 0x80))) ++ k--; ++ ++ *len = SIZEOF_UNSIGNED_LONG_INT - k; ++ ++ if (SIZEOF_UNSIGNED_LONG_INT - k > value_out_size) ++ /* VALUE_OUT is too short to contain the value conversion */ ++ return ASN1_MEM_ERROR; ++ ++ if (value_out != NULL) ++ { ++ for (k2 = k; k2 < SIZEOF_UNSIGNED_LONG_INT; k2++) ++ value_out[k2 - k] = val[k2]; ++ } ++ ++#if 0 ++ printf ("_asn1_convert_integer: valueIn=%s, lenOut=%d", value, *len); ++ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++) ++ printf (", vOut[%d]=%d", k, value_out[k]); ++ printf ("\n"); ++#endif ++ ++ return ASN1_SUCCESS; ++} ++ ++/* Appends a new element into the sequence (or set) defined by this ++ * node. The new element will have a name of '?number', where number ++ * is a monotonically increased serial number. ++ * ++ * The last element in the list may be provided in @pcache, to avoid ++ * traversing the list, an expensive operation in long lists. ++ * ++ * On success it returns in @pcache the added element (which is the ++ * tail in the list of added elements). ++ */ ++int ++_asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache) ++{ ++ asn1_node p, p2; ++ char temp[LTOSTR_MAX_SIZE + 1]; ++ long n; ++ ++ if (!node || !(node->down)) ++ return ASN1_GENERIC_ERROR; ++ ++ p = node->down; ++ while ((type_field (p->type) == ASN1_ETYPE_TAG) ++ || (type_field (p->type) == ASN1_ETYPE_SIZE)) ++ p = p->right; ++ ++ p2 = _asn1_copy_structure3 (p); ++ if (p2 == NULL) ++ return ASN1_GENERIC_ERROR; ++ ++ if (pcache == NULL || pcache->tail == NULL || pcache->head != node) ++ { ++ while (p->right) ++ { ++ p = p->right; ++ } ++ } ++ else ++ { ++ p = pcache->tail; ++ } ++ ++ _asn1_set_right (p, p2); ++ if (pcache) ++ { ++ pcache->head = node; ++ pcache->tail = p2; ++ } ++ ++ if (p->name[0] == 0) ++ _asn1_str_cpy (temp, sizeof (temp), "?1"); ++ else ++ { ++ n = strtol (p->name + 1, NULL, 0); ++ n++; ++ temp[0] = '?'; ++ _asn1_ltostr (n, temp + 1); ++ } ++ _asn1_set_name (p2, temp); ++ /* p2->type |= CONST_OPTION; */ ++ ++ return ASN1_SUCCESS; ++} ++ ++#if 0 ++/** ++ * asn1_write_value: ++ * @node_root: pointer to a structure ++ * @name: the name of the element inside the structure that you want to set. ++ * @ivalue: vector used to specify the value to set. If len is >0, ++ * VALUE must be a two's complement form integer. if len=0 *VALUE ++ * must be a null terminated string with an integer value. ++ * @len: number of bytes of *value to use to set the value: ++ * value[0]..value[len-1] or 0 if value is a null terminated string ++ * ++ * Set the value of one element inside a structure. ++ * ++ * If an element is OPTIONAL and you want to delete it, you must use ++ * the value=NULL and len=0. Using "pkix.asn": ++ * ++ * result=asn1_write_value(cert, "tbsCertificate.issuerUniqueID", ++ * NULL, 0); ++ * ++ * Description for each type: ++ * ++ * INTEGER: VALUE must contain a two's complement form integer. ++ * ++ * value[0]=0xFF , len=1 -> integer=-1. ++ * value[0]=0xFF value[1]=0xFF , len=2 -> integer=-1. ++ * value[0]=0x01 , len=1 -> integer= 1. ++ * value[0]=0x00 value[1]=0x01 , len=2 -> integer= 1. ++ * value="123" , len=0 -> integer= 123. ++ * ++ * ENUMERATED: As INTEGER (but only with not negative numbers). ++ * ++ * BOOLEAN: VALUE must be the null terminated string "TRUE" or ++ * "FALSE" and LEN != 0. ++ * ++ * value="TRUE" , len=1 -> boolean=TRUE. ++ * value="FALSE" , len=1 -> boolean=FALSE. ++ * ++ * OBJECT IDENTIFIER: VALUE must be a null terminated string with ++ * each number separated by a dot (e.g. "1.2.3.543.1"). LEN != 0. ++ * ++ * value="1 2 840 10040 4 3" , len=1 -> OID=dsa-with-sha. ++ * ++ * UTCTime: VALUE must be a null terminated string in one of these ++ * formats: "YYMMDDhhmmssZ", "YYMMDDhhmmssZ", ++ * "YYMMDDhhmmss+hh'mm'", "YYMMDDhhmmss-hh'mm'", ++ * "YYMMDDhhmm+hh'mm'", or "YYMMDDhhmm-hh'mm'". LEN != 0. ++ * ++ * value="9801011200Z" , len=1 -> time=Jannuary 1st, 1998 ++ * at 12h 00m Greenwich Mean Time ++ * ++ * GeneralizedTime: VALUE must be in one of this format: ++ * "YYYYMMDDhhmmss.sZ", "YYYYMMDDhhmmss.sZ", ++ * "YYYYMMDDhhmmss.s+hh'mm'", "YYYYMMDDhhmmss.s-hh'mm'", ++ * "YYYYMMDDhhmm+hh'mm'", or "YYYYMMDDhhmm-hh'mm'" where ss.s ++ * indicates the seconds with any precision like "10.1" or "01.02". ++ * LEN != 0 ++ * ++ * value="2001010112001.12-0700" , len=1 -> time=Jannuary ++ * 1st, 2001 at 12h 00m 01.12s Pacific Daylight Time ++ * ++ * OCTET STRING: VALUE contains the octet string and LEN is the ++ * number of octets. ++ * ++ * value="$\backslash$x01$\backslash$x02$\backslash$x03" , ++ * len=3 -> three bytes octet string ++ * ++ * GeneralString: VALUE contains the generalstring and LEN is the ++ * number of octets. ++ * ++ * value="$\backslash$x01$\backslash$x02$\backslash$x03" , ++ * len=3 -> three bytes generalstring ++ * ++ * BIT STRING: VALUE contains the bit string organized by bytes and ++ * LEN is the number of bits. ++ * ++ * value="$\backslash$xCF" , len=6 -> bit string="110011" (six ++ * bits) ++ * ++ * CHOICE: if NAME indicates a choice type, VALUE must specify one of ++ * the alternatives with a null terminated string. LEN != 0. Using ++ * "pkix.asn"\: ++ * ++ * result=asn1_write_value(cert, ++ * "certificate1.tbsCertificate.subject", "rdnSequence", ++ * 1); ++ * ++ * ANY: VALUE indicates the der encoding of a structure. LEN != 0. ++ * ++ * SEQUENCE OF: VALUE must be the null terminated string "NEW" and ++ * LEN != 0. With this instruction another element is appended in ++ * the sequence. The name of this element will be "?1" if it's the ++ * first one, "?2" for the second and so on. ++ * ++ * Using "pkix.asn"\: ++ * ++ * result=asn1_write_value(cert, ++ * "certificate1.tbsCertificate.subject.rdnSequence", "NEW", 1); ++ * ++ * SET OF: the same as SEQUENCE OF. Using "pkix.asn": ++ * ++ * result=asn1_write_value(cert, ++ * "tbsCertificate.subject.rdnSequence.?LAST", "NEW", 1); ++ * ++ * Returns: %ASN1_SUCCESS if the value was set, ++ * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, and ++ * %ASN1_VALUE_NOT_VALID if @ivalue has a wrong format. ++ **/ ++int ++asn1_write_value (asn1_node node_root, const char *name, ++ const void *ivalue, int len) ++{ ++ asn1_node node, p, p2; ++ unsigned char *temp, *value_temp = NULL, *default_temp = NULL; ++ int len2, k, k2, negative; ++ size_t i; ++ const unsigned char *value = ivalue; ++ unsigned int type; ++ ++ node = asn1_find_node (node_root, name); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ if ((node->type & CONST_OPTION) && (value == NULL) && (len == 0)) ++ { ++ asn1_delete_structure (&node); ++ return ASN1_SUCCESS; ++ } ++ ++ type = type_field (node->type); ++ ++ if ((type == ASN1_ETYPE_SEQUENCE_OF || type == ASN1_ETYPE_SET_OF) && (value == NULL) && (len == 0)) ++ { ++ p = node->down; ++ while ((type_field (p->type) == ASN1_ETYPE_TAG) ++ || (type_field (p->type) == ASN1_ETYPE_SIZE)) ++ p = p->right; ++ ++ while (p->right) ++ asn1_delete_structure (&p->right); ++ ++ return ASN1_SUCCESS; ++ } ++ ++ /* Don't allow element deletion for other types */ ++ if (value == NULL) ++ { ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ switch (type) ++ { ++ case ASN1_ETYPE_BOOLEAN: ++ if (!_asn1_strcmp (value, "TRUE")) ++ { ++ if (node->type & CONST_DEFAULT) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if (p->type & CONST_TRUE) ++ _asn1_set_value (node, NULL, 0); ++ else ++ _asn1_set_value (node, "T", 1); ++ } ++ else ++ _asn1_set_value (node, "T", 1); ++ } ++ else if (!_asn1_strcmp (value, "FALSE")) ++ { ++ if (node->type & CONST_DEFAULT) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if (p->type & CONST_FALSE) ++ _asn1_set_value (node, NULL, 0); ++ else ++ _asn1_set_value (node, "F", 1); ++ } ++ else ++ _asn1_set_value (node, "F", 1); ++ } ++ else ++ return ASN1_VALUE_NOT_VALID; ++ break; ++ case ASN1_ETYPE_INTEGER: ++ case ASN1_ETYPE_ENUMERATED: ++ if (len == 0) ++ { ++ if ((c_isdigit (value[0])) || (value[0] == '-')) ++ { ++ value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); ++ if (value_temp == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ ++ _asn1_convert_integer (value, value_temp, ++ SIZEOF_UNSIGNED_LONG_INT, &len); ++ } ++ else ++ { /* is an identifier like v1 */ ++ if (!(node->type & CONST_LIST)) ++ return ASN1_VALUE_NOT_VALID; ++ p = node->down; ++ while (p) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_CONSTANT) ++ { ++ if (!_asn1_strcmp (p->name, value)) ++ { ++ value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); ++ if (value_temp == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ ++ _asn1_convert_integer (p->value, ++ value_temp, ++ SIZEOF_UNSIGNED_LONG_INT, ++ &len); ++ break; ++ } ++ } ++ p = p->right; ++ } ++ if (p == NULL) ++ return ASN1_VALUE_NOT_VALID; ++ } ++ } ++ else ++ { /* len != 0 */ ++ value_temp = malloc (len); ++ if (value_temp == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ memcpy (value_temp, value, len); ++ } ++ ++ if (value_temp[0] & 0x80) ++ negative = 1; ++ else ++ negative = 0; ++ ++ if (negative && (type_field (node->type) == ASN1_ETYPE_ENUMERATED)) ++ { ++ free (value_temp); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ for (k = 0; k < len - 1; k++) ++ if (negative && (value_temp[k] != 0xFF)) ++ break; ++ else if (!negative && value_temp[k]) ++ break; ++ ++ if ((negative && !(value_temp[k] & 0x80)) || ++ (!negative && (value_temp[k] & 0x80))) ++ k--; ++ ++ _asn1_set_value_lv (node, value_temp + k, len - k); ++ ++ if (node->type & CONST_DEFAULT) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if ((c_isdigit (p->value[0])) || (p->value[0] == '-')) ++ { ++ default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); ++ if (default_temp == NULL) ++ { ++ free (value_temp); ++ return ASN1_MEM_ALLOC_ERROR; ++ } ++ ++ _asn1_convert_integer (p->value, default_temp, ++ SIZEOF_UNSIGNED_LONG_INT, &len2); ++ } ++ else ++ { /* is an identifier like v1 */ ++ if (!(node->type & CONST_LIST)) ++ { ++ free (value_temp); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ p2 = node->down; ++ while (p2) ++ { ++ if (type_field (p2->type) == ASN1_ETYPE_CONSTANT) ++ { ++ if (!_asn1_strcmp (p2->name, p->value)) ++ { ++ default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); ++ if (default_temp == NULL) ++ { ++ free (value_temp); ++ return ASN1_MEM_ALLOC_ERROR; ++ } ++ ++ _asn1_convert_integer (p2->value, ++ default_temp, ++ SIZEOF_UNSIGNED_LONG_INT, ++ &len2); ++ break; ++ } ++ } ++ p2 = p2->right; ++ } ++ if (p2 == NULL) ++ { ++ free (value_temp); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ } ++ ++ ++ if ((len - k) == len2) ++ { ++ for (k2 = 0; k2 < len2; k2++) ++ if (value_temp[k + k2] != default_temp[k2]) ++ { ++ break; ++ } ++ if (k2 == len2) ++ _asn1_set_value (node, NULL, 0); ++ } ++ free (default_temp); ++ } ++ free (value_temp); ++ break; ++ case ASN1_ETYPE_OBJECT_ID: ++ for (i = 0; i < _asn1_strlen (value); i++) ++ if ((!c_isdigit (value[i])) && (value[i] != '.') && (value[i] != '+')) ++ return ASN1_VALUE_NOT_VALID; ++ if (node->type & CONST_DEFAULT) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if (!_asn1_strcmp (value, p->value)) ++ { ++ _asn1_set_value (node, NULL, 0); ++ break; ++ } ++ } ++ _asn1_set_value (node, value, _asn1_strlen (value) + 1); ++ break; ++ case ASN1_ETYPE_UTC_TIME: ++ { ++ len = _asn1_strlen (value); ++ if (len < 11) ++ return ASN1_VALUE_NOT_VALID; ++ for (k = 0; k < 10; k++) ++ if (!c_isdigit (value[k])) ++ return ASN1_VALUE_NOT_VALID; ++ switch (len) ++ { ++ case 11: ++ if (value[10] != 'Z') ++ return ASN1_VALUE_NOT_VALID; ++ break; ++ case 13: ++ if ((!c_isdigit (value[10])) || (!c_isdigit (value[11])) || ++ (value[12] != 'Z')) ++ return ASN1_VALUE_NOT_VALID; ++ break; ++ case 15: ++ if ((value[10] != '+') && (value[10] != '-')) ++ return ASN1_VALUE_NOT_VALID; ++ for (k = 11; k < 15; k++) ++ if (!c_isdigit (value[k])) ++ return ASN1_VALUE_NOT_VALID; ++ break; ++ case 17: ++ if ((!c_isdigit (value[10])) || (!c_isdigit (value[11]))) ++ return ASN1_VALUE_NOT_VALID; ++ if ((value[12] != '+') && (value[12] != '-')) ++ return ASN1_VALUE_NOT_VALID; ++ for (k = 13; k < 17; k++) ++ if (!c_isdigit (value[k])) ++ return ASN1_VALUE_NOT_VALID; ++ break; ++ default: ++ return ASN1_VALUE_NOT_FOUND; ++ } ++ _asn1_set_value (node, value, len); ++ } ++ break; ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ len = _asn1_strlen (value); ++ _asn1_set_value (node, value, len); ++ break; ++ case ASN1_ETYPE_OCTET_STRING: ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ if (len == 0) ++ len = _asn1_strlen (value); ++ _asn1_set_value_lv (node, value, len); ++ break; ++ case ASN1_ETYPE_BIT_STRING: ++ if (len == 0) ++ len = _asn1_strlen (value); ++ asn1_length_der ((len >> 3) + 2, NULL, &len2); ++ temp = malloc ((len >> 3) + 2 + len2); ++ if (temp == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ ++ asn1_bit_der (value, len, temp, &len2); ++ _asn1_set_value_m (node, temp, len2); ++ temp = NULL; ++ break; ++ case ASN1_ETYPE_CHOICE: ++ p = node->down; ++ while (p) ++ { ++ if (!_asn1_strcmp (p->name, value)) ++ { ++ p2 = node->down; ++ while (p2) ++ { ++ if (p2 != p) ++ { ++ asn1_delete_structure (&p2); ++ p2 = node->down; ++ } ++ else ++ p2 = p2->right; ++ } ++ break; ++ } ++ p = p->right; ++ } ++ if (!p) ++ return ASN1_ELEMENT_NOT_FOUND; ++ break; ++ case ASN1_ETYPE_ANY: ++ _asn1_set_value_lv (node, value, len); ++ break; ++ case ASN1_ETYPE_SEQUENCE_OF: ++ case ASN1_ETYPE_SET_OF: ++ if (_asn1_strcmp (value, "NEW")) ++ return ASN1_VALUE_NOT_VALID; ++ _asn1_append_sequence_set (node, NULL); ++ break; ++ default: ++ return ASN1_ELEMENT_NOT_FOUND; ++ break; ++ } ++ ++ return ASN1_SUCCESS; ++} ++#endif ++ ++#define PUT_VALUE( ptr, ptr_size, data, data_size) \ ++ *len = data_size; \ ++ if (ptr_size < data_size) { \ ++ return ASN1_MEM_ERROR; \ ++ } else { \ ++ if (ptr && data_size > 0) \ ++ memcpy (ptr, data, data_size); \ ++ } ++ ++#define PUT_STR_VALUE( ptr, ptr_size, data) \ ++ *len = _asn1_strlen (data) + 1; \ ++ if (ptr_size < *len) { \ ++ return ASN1_MEM_ERROR; \ ++ } else { \ ++ /* this strcpy is checked */ \ ++ if (ptr) { \ ++ _asn1_strcpy (ptr, data); \ ++ } \ ++ } ++ ++#define PUT_AS_STR_VALUE( ptr, ptr_size, data, data_size) \ ++ *len = data_size + 1; \ ++ if (ptr_size < *len) { \ ++ return ASN1_MEM_ERROR; \ ++ } else { \ ++ /* this strcpy is checked */ \ ++ if (ptr) { \ ++ if (data_size > 0) \ ++ memcpy (ptr, data, data_size); \ ++ ptr[data_size] = 0; \ ++ } \ ++ } ++ ++#define ADD_STR_VALUE( ptr, ptr_size, data) \ ++ *len += _asn1_strlen(data); \ ++ if (ptr_size < (int) *len) { \ ++ (*len)++; \ ++ return ASN1_MEM_ERROR; \ ++ } else { \ ++ /* this strcat is checked */ \ ++ if (ptr) _asn1_strcat (ptr, data); \ ++ } ++ ++/** ++ * asn1_read_value: ++ * @root: pointer to a structure. ++ * @name: the name of the element inside a structure that you want to read. ++ * @ivalue: vector that will contain the element's content, must be a ++ * pointer to memory cells already allocated (may be %NULL). ++ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy ++ * holds the sizeof value. ++ * ++ * Returns the value of one element inside a structure. ++ * If an element is OPTIONAL and this returns ++ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present ++ * in the der encoding that created the structure. The first element ++ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and ++ * so on. If the @root provided is a node to specific sequence element, ++ * then the keyword "?CURRENT" is also acceptable and indicates the ++ * current sequence element of this node. ++ * ++ * Note that there can be valid values with length zero. In these case ++ * this function will succeed and @len will be zero. ++ * ++ * INTEGER: VALUE will contain a two's complement form integer. ++ * ++ * integer=-1 -> value[0]=0xFF , len=1. ++ * integer=1 -> value[0]=0x01 , len=1. ++ * ++ * ENUMERATED: As INTEGER (but only with not negative numbers). ++ * ++ * BOOLEAN: VALUE will be the null terminated string "TRUE" or ++ * "FALSE" and LEN=5 or LEN=6. ++ * ++ * OBJECT IDENTIFIER: VALUE will be a null terminated string with ++ * each number separated by a dot (i.e. "1.2.3.543.1"). ++ * ++ * LEN = strlen(VALUE)+1 ++ * ++ * UTCTime: VALUE will be a null terminated string in one of these ++ * formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'". ++ * LEN=strlen(VALUE)+1. ++ * ++ * GeneralizedTime: VALUE will be a null terminated string in the ++ * same format used to set the value. ++ * ++ * OCTET STRING: VALUE will contain the octet string and LEN will be ++ * the number of octets. ++ * ++ * GeneralString: VALUE will contain the generalstring and LEN will ++ * be the number of octets. ++ * ++ * BIT STRING: VALUE will contain the bit string organized by bytes ++ * and LEN will be the number of bits. ++ * ++ * CHOICE: If NAME indicates a choice type, VALUE will specify the ++ * alternative selected. ++ * ++ * ANY: If NAME indicates an any type, VALUE will indicate the DER ++ * encoding of the structure actually used. ++ * ++ * Returns: %ASN1_SUCCESS if value is returned, ++ * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, ++ * %ASN1_VALUE_NOT_FOUND if there isn't any value for the element ++ * selected, and %ASN1_MEM_ERROR if The value vector isn't big enough ++ * to store the result, and in this case @len will contain the number of ++ * bytes needed. On the occasion that the stored data are of zero-length ++ * this function may return %ASN1_SUCCESS even if the provided @len is zero. ++ **/ ++int ++asn1_read_value (asn1_node_const root, const char *name, void *ivalue, int *len) ++{ ++ return asn1_read_value_type (root, name, ivalue, len, NULL); ++} ++ ++/** ++ * asn1_read_value_type: ++ * @root: pointer to a structure. ++ * @name: the name of the element inside a structure that you want to read. ++ * @ivalue: vector that will contain the element's content, must be a ++ * pointer to memory cells already allocated (may be %NULL). ++ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy ++ * holds the sizeof value. ++ * @etype: The type of the value read (ASN1_ETYPE) ++ * ++ * Returns the type and value of one element inside a structure. ++ * If an element is OPTIONAL and this returns ++ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present ++ * in the der encoding that created the structure. The first element ++ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and ++ * so on. If the @root provided is a node to specific sequence element, ++ * then the keyword "?CURRENT" is also acceptable and indicates the ++ * current sequence element of this node. ++ * ++ * Note that there can be valid values with length zero. In these case ++ * this function will succeed and @len will be zero. ++ * ++ * ++ * INTEGER: VALUE will contain a two's complement form integer. ++ * ++ * integer=-1 -> value[0]=0xFF , len=1. ++ * integer=1 -> value[0]=0x01 , len=1. ++ * ++ * ENUMERATED: As INTEGER (but only with not negative numbers). ++ * ++ * BOOLEAN: VALUE will be the null terminated string "TRUE" or ++ * "FALSE" and LEN=5 or LEN=6. ++ * ++ * OBJECT IDENTIFIER: VALUE will be a null terminated string with ++ * each number separated by a dot (i.e. "1.2.3.543.1"). ++ * ++ * LEN = strlen(VALUE)+1 ++ * ++ * UTCTime: VALUE will be a null terminated string in one of these ++ * formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'". ++ * LEN=strlen(VALUE)+1. ++ * ++ * GeneralizedTime: VALUE will be a null terminated string in the ++ * same format used to set the value. ++ * ++ * OCTET STRING: VALUE will contain the octet string and LEN will be ++ * the number of octets. ++ * ++ * GeneralString: VALUE will contain the generalstring and LEN will ++ * be the number of octets. ++ * ++ * BIT STRING: VALUE will contain the bit string organized by bytes ++ * and LEN will be the number of bits. ++ * ++ * CHOICE: If NAME indicates a choice type, VALUE will specify the ++ * alternative selected. ++ * ++ * ANY: If NAME indicates an any type, VALUE will indicate the DER ++ * encoding of the structure actually used. ++ * ++ * Returns: %ASN1_SUCCESS if value is returned, ++ * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, ++ * %ASN1_VALUE_NOT_FOUND if there isn't any value for the element ++ * selected, and %ASN1_MEM_ERROR if The value vector isn't big enough ++ * to store the result, and in this case @len will contain the number of ++ * bytes needed. On the occasion that the stored data are of zero-length ++ * this function may return %ASN1_SUCCESS even if the provided @len is zero. ++ **/ ++int ++asn1_read_value_type (asn1_node_const root, const char *name, void *ivalue, ++ int *len, unsigned int *etype) ++{ ++ asn1_node_const node, p, p2; ++ int len2, len3, result; ++ int value_size = *len; ++ unsigned char *value = ivalue; ++ unsigned type; ++ ++ node = asn1_find_node (root, name); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ type = type_field (node->type); ++ ++ if ((type != ASN1_ETYPE_NULL) && ++ (type != ASN1_ETYPE_CHOICE) && ++ !(node->type & CONST_DEFAULT) && !(node->type & CONST_ASSIGN) && ++ (node->value == NULL)) ++ return ASN1_VALUE_NOT_FOUND; ++ ++ if (etype) ++ *etype = type; ++ switch (type) ++ { ++ case ASN1_ETYPE_NULL: ++ PUT_STR_VALUE (value, value_size, "NULL"); ++ break; ++ case ASN1_ETYPE_BOOLEAN: ++ if ((node->type & CONST_DEFAULT) && (node->value == NULL)) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if (p->type & CONST_TRUE) ++ { ++ PUT_STR_VALUE (value, value_size, "TRUE"); ++ } ++ else ++ { ++ PUT_STR_VALUE (value, value_size, "FALSE"); ++ } ++ } ++ else if (node->value[0] == 'T') ++ { ++ PUT_STR_VALUE (value, value_size, "TRUE"); ++ } ++ else ++ { ++ PUT_STR_VALUE (value, value_size, "FALSE"); ++ } ++ break; ++ case ASN1_ETYPE_INTEGER: ++ case ASN1_ETYPE_ENUMERATED: ++ if ((node->type & CONST_DEFAULT) && (node->value == NULL)) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if ((c_isdigit (p->value[0])) || (p->value[0] == '-') ++ || (p->value[0] == '+')) ++ { ++ result = _asn1_convert_integer ++ (p->value, value, value_size, len); ++ if (result != ASN1_SUCCESS) ++ return result; ++ } ++ else ++ { /* is an identifier like v1 */ ++ p2 = node->down; ++ while (p2) ++ { ++ if (type_field (p2->type) == ASN1_ETYPE_CONSTANT) ++ { ++ if (!_asn1_strcmp (p2->name, p->value)) ++ { ++ result = _asn1_convert_integer ++ (p2->value, value, value_size, ++ len); ++ if (result != ASN1_SUCCESS) ++ return result; ++ break; ++ } ++ } ++ p2 = p2->right; ++ } ++ } ++ } ++ else ++ { ++ len2 = -1; ++ result = asn1_get_octet_der ++ (node->value, node->value_len, &len2, value, value_size, ++ len); ++ if (result != ASN1_SUCCESS) ++ return result; ++ } ++ break; ++ case ASN1_ETYPE_OBJECT_ID: ++ if (node->type & CONST_ASSIGN) ++ { ++ *len = 0; ++ if (value) ++ value[0] = 0; ++ p = node->down; ++ while (p) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_CONSTANT) ++ { ++ ADD_STR_VALUE (value, value_size, p->value); ++ if (p->right) ++ { ++ ADD_STR_VALUE (value, value_size, "."); ++ } ++ } ++ p = p->right; ++ } ++ (*len)++; ++ } ++ else if ((node->type & CONST_DEFAULT) && (node->value == NULL)) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ PUT_STR_VALUE (value, value_size, p->value); ++ } ++ else ++ { ++ PUT_STR_VALUE (value, value_size, node->value); ++ } ++ break; ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ case ASN1_ETYPE_UTC_TIME: ++ PUT_AS_STR_VALUE (value, value_size, node->value, node->value_len); ++ break; ++ case ASN1_ETYPE_OCTET_STRING: ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ len2 = -1; ++ result = asn1_get_octet_der ++ (node->value, node->value_len, &len2, value, value_size, ++ len); ++ if (result != ASN1_SUCCESS) ++ return result; ++ break; ++ case ASN1_ETYPE_BIT_STRING: ++ len2 = -1; ++ result = asn1_get_bit_der ++ (node->value, node->value_len, &len2, value, value_size, ++ len); ++ if (result != ASN1_SUCCESS) ++ return result; ++ break; ++ case ASN1_ETYPE_CHOICE: ++ PUT_STR_VALUE (value, value_size, node->down->name); ++ break; ++ case ASN1_ETYPE_ANY: ++ len3 = -1; ++ len2 = asn1_get_length_der (node->value, node->value_len, &len3); ++ if (len2 < 0) ++ return ASN1_DER_ERROR; ++ PUT_VALUE (value, value_size, node->value + len3, len2); ++ break; ++ default: ++ return ASN1_ELEMENT_NOT_FOUND; ++ break; ++ } ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_read_tag: ++ * @root: pointer to a structure ++ * @name: the name of the element inside a structure. ++ * @tagValue: variable that will contain the TAG value. ++ * @classValue: variable that will specify the TAG type. ++ * ++ * Returns the TAG and the CLASS of one element inside a structure. ++ * CLASS can have one of these constants: %ASN1_CLASS_APPLICATION, ++ * %ASN1_CLASS_UNIVERSAL, %ASN1_CLASS_PRIVATE or ++ * %ASN1_CLASS_CONTEXT_SPECIFIC. ++ * ++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if ++ * @name is not a valid element. ++ **/ ++int ++asn1_read_tag (asn1_node_const root, const char *name, int *tagValue, ++ int *classValue) ++{ ++ asn1_node node, p, pTag; ++ ++ node = asn1_find_node (root, name); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node->down; ++ ++ /* pTag will points to the IMPLICIT TAG */ ++ pTag = NULL; ++ if (node->type & CONST_TAG) ++ { ++ while (p) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_TAG) ++ { ++ if ((p->type & CONST_IMPLICIT) && (pTag == NULL)) ++ pTag = p; ++ else if (p->type & CONST_EXPLICIT) ++ pTag = NULL; ++ } ++ p = p->right; ++ } ++ } ++ ++ if (pTag) ++ { ++ *tagValue = _asn1_strtoul (pTag->value, NULL, 10); ++ ++ if (pTag->type & CONST_APPLICATION) ++ *classValue = ASN1_CLASS_APPLICATION; ++ else if (pTag->type & CONST_UNIVERSAL) ++ *classValue = ASN1_CLASS_UNIVERSAL; ++ else if (pTag->type & CONST_PRIVATE) ++ *classValue = ASN1_CLASS_PRIVATE; ++ else ++ *classValue = ASN1_CLASS_CONTEXT_SPECIFIC; ++ } ++ else ++ { ++ unsigned type = type_field (node->type); ++ *classValue = ASN1_CLASS_UNIVERSAL; ++ ++ switch (type) ++ { ++ CASE_HANDLED_ETYPES: ++ *tagValue = _asn1_tags[type].tag; ++ break; ++ case ASN1_ETYPE_TAG: ++ case ASN1_ETYPE_CHOICE: ++ case ASN1_ETYPE_ANY: ++ *tagValue = -1; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_read_node_value: ++ * @node: pointer to a node. ++ * @data: a point to a asn1_data_node_st ++ * ++ * Returns the value a data node inside a asn1_node structure. ++ * The data returned should be handled as constant values. ++ * ++ * Returns: %ASN1_SUCCESS if the node exists. ++ **/ ++int ++asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data) ++{ ++ data->name = node->name; ++ data->value = node->value; ++ data->value_len = node->value_len; ++ data->type = type_field (node->type); ++ ++ return ASN1_SUCCESS; ++} +diff --git a/grub-core/lib/libtasn1/lib/element.h b/grub-core/lib/libtasn1/lib/element.h +new file mode 100644 +index 000000000..440a33f4b +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/element.h +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (C) 2000-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#ifndef _ELEMENT_H ++#define _ELEMENT_H ++ ++ ++struct node_tail_cache_st ++{ ++ asn1_node head; /* the first element of the sequence */ ++ asn1_node tail; ++}; ++ ++int _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcached); ++ ++int _asn1_convert_integer (const unsigned char *value, ++ unsigned char *value_out, ++ int value_out_size, int *len); ++ ++void _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size); ++ ++#endif +diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c +new file mode 100644 +index 000000000..42785e862 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/errors.c +@@ -0,0 +1,103 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#include ++#ifdef STDC_HEADERS ++#include ++#endif ++ ++#define LIBTASN1_ERROR_ENTRY(name) { #name, name } ++ ++struct libtasn1_error_entry ++{ ++ const char *name; ++ int number; ++}; ++typedef struct libtasn1_error_entry libtasn1_error_entry; ++ ++static const libtasn1_error_entry error_algorithms[] = { ++ LIBTASN1_ERROR_ENTRY (ASN1_SUCCESS), ++ LIBTASN1_ERROR_ENTRY (ASN1_FILE_NOT_FOUND), ++ LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_FOUND), ++ LIBTASN1_ERROR_ENTRY (ASN1_IDENTIFIER_NOT_FOUND), ++ LIBTASN1_ERROR_ENTRY (ASN1_DER_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_FOUND), ++ LIBTASN1_ERROR_ENTRY (ASN1_GENERIC_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_VALID), ++ LIBTASN1_ERROR_ENTRY (ASN1_TAG_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_TAG_IMPLICIT), ++ LIBTASN1_ERROR_ENTRY (ASN1_ERROR_TYPE_ANY), ++ LIBTASN1_ERROR_ENTRY (ASN1_SYNTAX_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_MEM_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_MEM_ALLOC_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_DER_OVERFLOW), ++ LIBTASN1_ERROR_ENTRY (ASN1_NAME_TOO_LONG), ++ LIBTASN1_ERROR_ENTRY (ASN1_ARRAY_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_EMPTY), ++ LIBTASN1_ERROR_ENTRY (ASN1_TIME_ENCODING_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_RECURSION), ++ {0, 0} ++}; ++ ++ ++#if 0 ++/** ++ * asn1_perror: ++ * @error: is an error returned by a libtasn1 function. ++ * ++ * Prints a string to stderr with a description of an error. This ++ * function is like perror(). The only difference is that it accepts ++ * an error returned by a libtasn1 function. ++ * ++ * Since: 1.6 ++ **/ ++void ++asn1_perror (int error) ++{ ++ const char *str = asn1_strerror (error); ++ fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)"); ++} ++#endif ++ ++/** ++ * asn1_strerror: ++ * @error: is an error returned by a libtasn1 function. ++ * ++ * Returns a string with a description of an error. This function is ++ * similar to strerror. The only difference is that it accepts an ++ * error (number) returned by a libtasn1 function. ++ * ++ * Returns: Pointer to static zero-terminated string describing error ++ * code. ++ * ++ * Since: 1.6 ++ **/ ++const char * ++asn1_strerror (int error) ++{ ++ const libtasn1_error_entry *p; ++ ++ for (p = error_algorithms; p->name != NULL; p++) ++ if (p->number == error) ++ return p->name + sizeof ("ASN1_") - 1; ++ ++ return NULL; ++} +diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c +new file mode 100644 +index 000000000..e33875c2c +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/gstr.c +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#include ++#include "gstr.h" ++ ++/* These function are like strcat, strcpy. They only ++ * do bounds checking (they shouldn't cause buffer overruns), ++ * and they always produce null terminated strings. ++ * ++ * They should be used only with null terminated strings. ++ */ ++void ++_asn1_str_cat (char *dest, size_t dest_tot_size, const char *src) ++{ ++ size_t str_size = strlen (src); ++ size_t dest_size = strlen (dest); ++ ++ if (dest_tot_size - dest_size > str_size) ++ { ++ memcpy (dest + dest_size, src, str_size + 1); ++ } ++ else ++ { ++ if (dest_tot_size - dest_size > 0) ++ { ++ memcpy (dest + dest_size, src, (dest_tot_size - dest_size) - 1); ++ dest[dest_tot_size - 1] = 0; ++ } ++ } ++} ++ ++/* Returns the bytes copied (not including the null terminator) */ ++unsigned int ++_asn1_str_cpy (char *dest, size_t dest_tot_size, const char *src) ++{ ++ size_t str_size = strlen (src); ++ ++ if (dest_tot_size > str_size) ++ { ++ strcpy (dest, src); ++ return str_size; ++ } ++ else ++ { ++ if (dest_tot_size > 0) ++ { ++ str_size = dest_tot_size - 1; ++ memcpy (dest, src, str_size); ++ dest[str_size] = 0; ++ return str_size; ++ } ++ else ++ return 0; ++ } ++} +diff --git a/grub-core/lib/libtasn1/lib/gstr.h b/grub-core/lib/libtasn1/lib/gstr.h +new file mode 100644 +index 000000000..48229844f +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/gstr.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#ifndef GSTR_H ++# define GSTR_H ++ ++unsigned int _asn1_str_cpy (char *dest, size_t dest_tot_size, ++ const char *src); ++void _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src); ++ ++#define Estrcpy(x,y) _asn1_str_cpy(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y) ++#define Estrcat(x,y) _asn1_str_cat(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y) ++ ++inline static ++void safe_memset(void *data, int c, size_t size) ++{ ++ volatile unsigned volatile_zero = 0; ++ volatile char *vdata = (volatile char*)data; ++ ++ /* This is based on a nice trick for safe memset, ++ * sent by David Jacobson in the openssl-dev mailing list. ++ */ ++ ++ if (size > 0) do { ++ memset(data, c, size); ++ } while(vdata[volatile_zero] != c); ++} ++ ++#endif /* GSTR_H */ +diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h +new file mode 100644 +index 000000000..4a568efee +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/int.h +@@ -0,0 +1,221 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#ifndef INT_H ++#define INT_H ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++ ++#ifdef HAVE_SYS_TYPES_H ++#include ++#endif ++ ++#include "grub/libtasn1.h" ++ ++#define ASN1_SMALL_VALUE_SIZE 16 ++ ++/* This structure is also in libtasn1.h, but then contains less ++ fields. You cannot make any modifications to these first fields ++ without breaking ABI. */ ++struct asn1_node_st ++{ ++ /* public fields: */ ++ char name[ASN1_MAX_NAME_SIZE + 1]; /* Node name */ ++ unsigned int name_hash; ++ unsigned int type; /* Node type */ ++ unsigned char *value; /* Node value */ ++ int value_len; ++ asn1_node down; /* Pointer to the son node */ ++ asn1_node right; /* Pointer to the brother node */ ++ asn1_node left; /* Pointer to the next list element */ ++ /* private fields: */ ++ unsigned char small_value[ASN1_SMALL_VALUE_SIZE]; /* For small values */ ++ ++ /* values used during decoding/coding */ ++ int tmp_ival; ++ unsigned start; /* the start of the DER sequence - if decoded */ ++ unsigned end; /* the end of the DER sequence - if decoded */ ++}; ++ ++typedef struct tag_and_class_st ++{ ++ unsigned tag; ++ unsigned class; ++ const char *desc; ++} tag_and_class_st; ++ ++/* the types that are handled in _asn1_tags */ ++#define CASE_HANDLED_ETYPES \ ++ case ASN1_ETYPE_NULL: \ ++ case ASN1_ETYPE_BOOLEAN: \ ++ case ASN1_ETYPE_INTEGER: \ ++ case ASN1_ETYPE_ENUMERATED: \ ++ case ASN1_ETYPE_OBJECT_ID: \ ++ case ASN1_ETYPE_OCTET_STRING: \ ++ case ASN1_ETYPE_GENERALSTRING: \ ++ case ASN1_ETYPE_NUMERIC_STRING: \ ++ case ASN1_ETYPE_IA5_STRING: \ ++ case ASN1_ETYPE_TELETEX_STRING: \ ++ case ASN1_ETYPE_PRINTABLE_STRING: \ ++ case ASN1_ETYPE_UNIVERSAL_STRING: \ ++ case ASN1_ETYPE_BMP_STRING: \ ++ case ASN1_ETYPE_UTF8_STRING: \ ++ case ASN1_ETYPE_VISIBLE_STRING: \ ++ case ASN1_ETYPE_BIT_STRING: \ ++ case ASN1_ETYPE_SEQUENCE: \ ++ case ASN1_ETYPE_SEQUENCE_OF: \ ++ case ASN1_ETYPE_SET: \ ++ case ASN1_ETYPE_UTC_TIME: \ ++ case ASN1_ETYPE_GENERALIZED_TIME: \ ++ case ASN1_ETYPE_SET_OF ++ ++#define ETYPE_TAG(etype) (_asn1_tags[etype].tag) ++#define ETYPE_CLASS(etype) (_asn1_tags[etype].class) ++#define ETYPE_OK(etype) (((etype) != ASN1_ETYPE_INVALID && \ ++ (etype) <= _asn1_tags_size && \ ++ _asn1_tags[(etype)].desc != NULL)?1:0) ++ ++#define ETYPE_IS_STRING(etype) ((etype == ASN1_ETYPE_GENERALSTRING || \ ++ etype == ASN1_ETYPE_NUMERIC_STRING || etype == ASN1_ETYPE_IA5_STRING || \ ++ etype == ASN1_ETYPE_TELETEX_STRING || etype == ASN1_ETYPE_PRINTABLE_STRING || \ ++ etype == ASN1_ETYPE_UNIVERSAL_STRING || etype == ASN1_ETYPE_BMP_STRING || \ ++ etype == ASN1_ETYPE_UTF8_STRING || etype == ASN1_ETYPE_VISIBLE_STRING || \ ++ etype == ASN1_ETYPE_OCTET_STRING)?1:0) ++ ++extern unsigned int _asn1_tags_size; ++extern const tag_and_class_st _asn1_tags[]; ++ ++#define _asn1_strlen(s) strlen((const char *) s) ++#define _asn1_strtol(n,e,b) strtol((const char *) n, e, b) ++#define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b) ++#define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b) ++#define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b) ++#define _asn1_strcat(a,b) memcpy((char *)a + strlen((const char *)a), (const char *)b, strlen((const char *)b) + 1) ++ ++#if SIZEOF_UNSIGNED_LONG_INT == 8 ++# define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b) ++#else ++# define _asn1_strtou64(n,e,b) strtoull((const char *) n, e, b) ++#endif ++ ++#define MAX_LOG_SIZE 1024 /* maximum number of characters of a log message */ ++ ++/* Define used for visiting trees. */ ++#define UP 1 ++#define RIGHT 2 ++#define DOWN 3 ++ ++/***********************************************************************/ ++/* List of constants to better specify the type of typedef asn1_node_st. */ ++/***********************************************************************/ ++/* Used with TYPE_TAG */ ++#define CONST_UNIVERSAL (1U<<8) ++#define CONST_PRIVATE (1U<<9) ++#define CONST_APPLICATION (1U<<10) ++#define CONST_EXPLICIT (1U<<11) ++#define CONST_IMPLICIT (1U<<12) ++ ++#define CONST_TAG (1U<<13) /* Used in ASN.1 assignement */ ++#define CONST_OPTION (1U<<14) ++#define CONST_DEFAULT (1U<<15) ++#define CONST_TRUE (1U<<16) ++#define CONST_FALSE (1U<<17) ++ ++#define CONST_LIST (1U<<18) /* Used with TYPE_INTEGER and TYPE_BIT_STRING */ ++#define CONST_MIN_MAX (1U<<19) ++ ++#define CONST_1_PARAM (1U<<20) ++ ++#define CONST_SIZE (1U<<21) ++ ++#define CONST_DEFINED_BY (1U<<22) ++ ++/* Those two are deprecated and used for backwards compatibility */ ++#define CONST_GENERALIZED (1U<<23) ++#define CONST_UTC (1U<<24) ++ ++/* #define CONST_IMPORTS (1U<<25) */ ++ ++#define CONST_NOT_USED (1U<<26) ++#define CONST_SET (1U<<27) ++#define CONST_ASSIGN (1U<<28) ++ ++#define CONST_DOWN (1U<<29) ++#define CONST_RIGHT (1U<<30) ++ ++ ++#define ASN1_ETYPE_TIME 17 ++/****************************************/ ++/* Returns the first 8 bits. */ ++/* Used with the field type of asn1_node_st */ ++/****************************************/ ++inline static unsigned int ++type_field (unsigned int ntype) ++{ ++ return (ntype & 0xff); ++} ++ ++/* To convert old types from a static structure */ ++inline static unsigned int ++convert_old_type (unsigned int ntype) ++{ ++ unsigned int type = ntype & 0xff; ++ if (type == ASN1_ETYPE_TIME) ++ { ++ if (ntype & CONST_UTC) ++ type = ASN1_ETYPE_UTC_TIME; ++ else ++ type = ASN1_ETYPE_GENERALIZED_TIME; ++ ++ ntype &= ~(CONST_UTC | CONST_GENERALIZED); ++ ntype &= 0xffffff00; ++ ntype |= type; ++ ++ return ntype; ++ } ++ else ++ return ntype; ++} ++ ++static inline ++void *_asn1_realloc(void *ptr, size_t size) ++{ ++ void *ret; ++ ++ if (size == 0) ++ return ptr; ++ ++ ret = realloc(ptr, size); ++ if (ret == NULL) ++ { ++ free(ptr); ++ } ++ return ret; ++} ++ ++#endif /* INT_H */ +diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c +new file mode 100644 +index 000000000..89c9be69d +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/parser_aux.c +@@ -0,0 +1,1174 @@ ++/* ++ * Copyright (C) 2000-2016 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#include // WORD_BIT ++ ++#include "int.h" ++#include "parser_aux.h" ++#include "gstr.h" ++#include "structure.h" ++#include "element.h" ++ ++#define c_isdigit grub_isdigit ++ ++char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1]; /* identifier name not found */ ++ ++/* Return a hash of the N bytes of X using the method described by ++ Bruno Haible in https://www.haible.de/bruno/hashfunc.html. ++ Note that while many hash functions reduce their result via modulo ++ to a 0..table_size-1 range, this function does not do that. ++ ++ This implementation has been changed from size_t -> unsigned int. */ ++ ++#ifdef __clang__ ++__attribute__((no_sanitize("integer"))) ++#endif ++__attribute__((__pure__)) ++static unsigned int ++_asn1_hash_name (const char *x) ++{ ++ const unsigned char *s = (unsigned char *) x; ++ unsigned h = 0; ++ ++ while (*s) ++ h = (*s++) + ((h << 9) | (h >> (WORD_BIT - 9))); ++ ++ return h; ++} ++ ++/******************************************************/ ++/* Function : _asn1_add_static_node */ ++/* Description: creates a new NODE_ASN element and */ ++/* puts it in the list pointed by e_list. */ ++/* Parameters: */ ++/* e_list: of type list_type; must be NULL initially */ ++/* type: type of the new element (see ASN1_ETYPE_ */ ++/* and CONST_ constants). */ ++/* Return: pointer to the new element. */ ++/******************************************************/ ++asn1_node ++_asn1_add_static_node (list_type **e_list, unsigned int type) ++{ ++ list_type *p; ++ asn1_node punt; ++ ++ punt = calloc (1, sizeof (struct asn1_node_st)); ++ if (punt == NULL) ++ return NULL; ++ ++ p = malloc (sizeof (list_type)); ++ if (p == NULL) ++ { ++ free (punt); ++ return NULL; ++ } ++ ++ p->node = punt; ++ p->next = *e_list; ++ *e_list = p; ++ ++ punt->type = type; ++ ++ return punt; ++} ++ ++static ++int _asn1_add_static_node2 (list_type **e_list, asn1_node node) ++{ ++ list_type *p; ++ ++ p = malloc (sizeof (list_type)); ++ if (p == NULL) ++ { ++ return -1; ++ } ++ ++ p->node = node; ++ p->next = *e_list; ++ *e_list = p; ++ ++ return 0; ++} ++ ++/** ++ * asn1_find_node: ++ * @pointer: NODE_ASN element pointer. ++ * @name: null terminated string with the element's name to find. ++ * ++ * Searches for an element called @name starting from @pointer. The ++ * name is composed by different identifiers separated by dots. When ++ * *@pointer has a name, the first identifier must be the name of ++ * *@pointer, otherwise it must be the name of one child of *@pointer. ++ * ++ * Returns: the search result, or %NULL if not found. ++ **/ ++asn1_node ++asn1_find_node (asn1_node_const pointer, const char *name) ++{ ++ asn1_node_const p; ++ char *n_end, n[ASN1_MAX_NAME_SIZE + 1]; ++ const char *n_start; ++ unsigned int nsize; ++ unsigned int nhash; ++ ++ if (pointer == NULL) ++ return NULL; ++ ++ if (name == NULL) ++ return NULL; ++ ++ p = pointer; ++ n_start = name; ++ ++ if (name[0] == '?' && name[1] == 'C' && p->name[0] == '?') ++ { /* ?CURRENT */ ++ n_start = strchr(n_start, '.'); ++ if (n_start) ++ n_start++; ++ } ++ else if (p->name[0] != 0) ++ { /* has *pointer got a name ? */ ++ n_end = strchr (n_start, '.'); /* search the first dot */ ++ if (n_end) ++ { ++ nsize = n_end - n_start; ++ if (nsize >= sizeof(n)) ++ return NULL; ++ ++ memcpy (n, n_start, nsize); ++ n[nsize] = 0; ++ n_start = n_end; ++ n_start++; ++ ++ nhash = _asn1_hash_name (n); ++ } ++ else ++ { ++ _asn1_str_cpy (n, sizeof (n), n_start); ++ nhash = _asn1_hash_name (n); ++ ++ n_start = NULL; ++ } ++ ++ while (p) ++ { ++ if (nhash == p->name_hash && (!strcmp (p->name, n))) ++ break; ++ else ++ p = p->right; ++ } /* while */ ++ ++ if (p == NULL) ++ return NULL; ++ } ++ else ++ { /* *pointer doesn't have a name */ ++ if (n_start[0] == 0) ++ return (asn1_node) p; ++ } ++ ++ while (n_start) ++ { /* Has the end of NAME been reached? */ ++ n_end = strchr (n_start, '.'); /* search the next dot */ ++ if (n_end) ++ { ++ nsize = n_end - n_start; ++ if (nsize >= sizeof(n)) ++ return NULL; ++ ++ memcpy (n, n_start, nsize); ++ n[nsize] = 0; ++ n_start = n_end; ++ n_start++; ++ ++ nhash = _asn1_hash_name (n); ++ } ++ else ++ { ++ _asn1_str_cpy (n, sizeof (n), n_start); ++ nhash = _asn1_hash_name (n); ++ n_start = NULL; ++ } ++ ++ if (p->down == NULL) ++ return NULL; ++ ++ p = p->down; ++ if (p == NULL) ++ return NULL; ++ ++ /* The identifier "?LAST" indicates the last element ++ in the right chain. */ ++ if (n[0] == '?' && n[1] == 'L') /* ?LAST */ ++ { ++ while (p->right) ++ p = p->right; ++ } ++ else ++ { /* no "?LAST" */ ++ while (p) ++ { ++ if (p->name_hash == nhash && !strcmp (p->name, n)) ++ break; ++ else ++ p = p->right; ++ } ++ } ++ if (p == NULL) ++ return NULL; ++ } /* while */ ++ ++ return (asn1_node) p; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_set_value */ ++/* Description: sets the field VALUE in a NODE_ASN element. The */ ++/* previous value (if exist) will be lost */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* value: pointer to the value that you want to set. */ ++/* len: character number of value. */ ++/* Return: pointer to the NODE_ASN element. */ ++/******************************************************************/ ++asn1_node ++_asn1_set_value (asn1_node node, const void *value, unsigned int len) ++{ ++ if (node == NULL) ++ return node; ++ if (node->value) ++ { ++ if (node->value != node->small_value) ++ free (node->value); ++ node->value = NULL; ++ node->value_len = 0; ++ } ++ ++ if (!len) ++ return node; ++ ++ if (len < sizeof (node->small_value)) ++ { ++ node->value = node->small_value; ++ } ++ else ++ { ++ node->value = malloc (len); ++ if (node->value == NULL) ++ return NULL; ++ } ++ node->value_len = len; ++ ++ memcpy (node->value, value, len); ++ return node; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_set_value_lv */ ++/* Description: sets the field VALUE in a NODE_ASN element. The */ ++/* previous value (if exist) will be lost. The value */ ++/* given is stored as an length-value format (LV */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* value: pointer to the value that you want to set. */ ++/* len: character number of value. */ ++/* Return: pointer to the NODE_ASN element. */ ++/******************************************************************/ ++asn1_node ++_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len) ++{ ++ int len2; ++ void *temp; ++ ++ if (node == NULL) ++ return node; ++ ++ asn1_length_der (len, NULL, &len2); ++ temp = malloc (len + len2); ++ if (temp == NULL) ++ return NULL; ++ ++ asn1_octet_der (value, len, temp, &len2); ++ return _asn1_set_value_m (node, temp, len2); ++} ++ ++/* the same as _asn1_set_value except that it sets an already malloc'ed ++ * value. ++ */ ++asn1_node ++_asn1_set_value_m (asn1_node node, void *value, unsigned int len) ++{ ++ if (node == NULL) ++ return node; ++ ++ if (node->value) ++ { ++ if (node->value != node->small_value) ++ free (node->value); ++ node->value = NULL; ++ node->value_len = 0; ++ } ++ ++ if (!len) ++ return node; ++ ++ node->value = value; ++ node->value_len = len; ++ ++ return node; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_append_value */ ++/* Description: appends to the field VALUE in a NODE_ASN element. */ ++/* */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* value: pointer to the value that you want to be appended. */ ++/* len: character number of value. */ ++/* Return: pointer to the NODE_ASN element. */ ++/******************************************************************/ ++asn1_node ++_asn1_append_value (asn1_node node, const void *value, unsigned int len) ++{ ++ if (node == NULL) ++ return node; ++ ++ if (node->value == NULL) ++ return _asn1_set_value (node, value, len); ++ ++ if (len == 0) ++ return node; ++ ++ if (node->value == node->small_value) ++ { ++ /* value is in node */ ++ int prev_len = node->value_len; ++ node->value_len += len; ++ node->value = malloc (node->value_len); ++ if (node->value == NULL) ++ { ++ node->value_len = 0; ++ return NULL; ++ } ++ ++ if (prev_len > 0) ++ memcpy (node->value, node->small_value, prev_len); ++ ++ memcpy (&node->value[prev_len], value, len); ++ ++ return node; ++ } ++ else /* if (node->value != NULL && node->value != node->small_value) */ ++ { ++ /* value is allocated */ ++ int prev_len = node->value_len; ++ node->value_len += len; ++ ++ node->value = _asn1_realloc (node->value, node->value_len); ++ if (node->value == NULL) ++ { ++ node->value_len = 0; ++ return NULL; ++ } ++ ++ memcpy (&node->value[prev_len], value, len); ++ ++ return node; ++ } ++} ++ ++/******************************************************************/ ++/* Function : _asn1_set_name */ ++/* Description: sets the field NAME in a NODE_ASN element. The */ ++/* previous value (if exist) will be lost */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* name: a null terminated string with the name that you want */ ++/* to set. */ ++/* Return: pointer to the NODE_ASN element. */ ++/******************************************************************/ ++asn1_node ++_asn1_set_name (asn1_node node, const char *name) ++{ ++ if (node == NULL) ++ return node; ++ ++ _asn1_str_cpy (node->name, sizeof (node->name), name ? name : ""); ++ node->name_hash = _asn1_hash_name (node->name); ++ ++ return node; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_cpy_name */ ++/* Description: copies the field NAME in a NODE_ASN element. */ ++/* Parameters: */ ++/* dst: a dest element pointer. */ ++/* src: a source element pointer. */ ++/* Return: pointer to the NODE_ASN element. */ ++/******************************************************************/ ++asn1_node ++_asn1_cpy_name (asn1_node dst, asn1_node_const src) ++{ ++ if (dst == NULL) ++ return dst; ++ ++ if (src == NULL) ++ { ++ dst->name[0] = 0; ++ dst->name_hash = _asn1_hash_name (dst->name); ++ return dst; ++ } ++ ++ _asn1_str_cpy (dst->name, sizeof (dst->name), src->name); ++ dst->name_hash = src->name_hash; ++ ++ return dst; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_set_right */ ++/* Description: sets the field RIGHT in a NODE_ASN element. */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* right: pointer to a NODE_ASN element that you want be pointed*/ ++/* by NODE. */ ++/* Return: pointer to *NODE. */ ++/******************************************************************/ ++asn1_node ++_asn1_set_right (asn1_node node, asn1_node right) ++{ ++ if (node == NULL) ++ return node; ++ node->right = right; ++ if (right) ++ right->left = node; ++ return node; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_get_last_right */ ++/* Description: return the last element along the right chain. */ ++/* Parameters: */ ++/* node: starting element pointer. */ ++/* Return: pointer to the last element along the right chain. */ ++/******************************************************************/ ++asn1_node ++_asn1_get_last_right (asn1_node_const node) ++{ ++ asn1_node_const p; ++ ++ if (node == NULL) ++ return NULL; ++ p = node; ++ while (p->right) ++ p = p->right; ++ return (asn1_node) p; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_remove_node */ ++/* Description: gets free the memory allocated for an NODE_ASN */ ++/* element (not the elements pointed by it). */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* flags: ASN1_DELETE_FLAG_* */ ++/******************************************************************/ ++void ++_asn1_remove_node (asn1_node node, unsigned int flags) ++{ ++ if (node == NULL) ++ return; ++ ++ if (node->value != NULL) ++ { ++ if (flags & ASN1_DELETE_FLAG_ZEROIZE) ++ { ++ safe_memset(node->value, 0, node->value_len); ++ } ++ ++ if (node->value != node->small_value) ++ free (node->value); ++ } ++ free (node); ++} ++ ++/******************************************************************/ ++/* Function : _asn1_find_up */ ++/* Description: return the father of the NODE_ASN element. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* Return: Null if not found. */ ++/******************************************************************/ ++asn1_node ++_asn1_find_up (asn1_node_const node) ++{ ++ asn1_node_const p; ++ ++ if (node == NULL) ++ return NULL; ++ ++ p = node; ++ ++ while ((p->left != NULL) && (p->left->right == p)) ++ p = p->left; ++ ++ return p->left; ++} ++ ++static ++unsigned _asn1_is_up (asn1_node_const up_cand, asn1_node_const down) ++{ ++ asn1_node_const d, u; ++ ++ if (up_cand == NULL || down == NULL) ++ return 0; ++ ++ d = down; ++ ++ while ((u = _asn1_find_up(d)) != NULL && u != d) ++ { ++ if (u == up_cand) ++ return 1; ++ d = u; ++ } ++ ++ return 0; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_delete_node_from_list */ ++/* Description: deletes the list element given */ ++/******************************************************************/ ++void ++_asn1_delete_node_from_list (list_type *list, asn1_node node) ++{ ++ list_type *p = list; ++ ++ while (p) ++ { ++ if (p->node == node) ++ p->node = NULL; ++ p = p->next; ++ } ++} ++ ++/******************************************************************/ ++/* Function : _asn1_delete_list */ ++/* Description: deletes the list elements (not the elements */ ++/* pointed by them). */ ++/******************************************************************/ ++void ++_asn1_delete_list (list_type *e_list) ++{ ++ list_type *p; ++ ++ while (e_list) ++ { ++ p = e_list; ++ e_list = e_list->next; ++ free (p); ++ } ++} ++ ++/******************************************************************/ ++/* Function : _asn1_delete_list_and nodes */ ++/* Description: deletes the list elements and the elements */ ++/* pointed by them. */ ++/******************************************************************/ ++void ++_asn1_delete_list_and_nodes (list_type *e_list) ++{ ++ list_type *p; ++ ++ while (e_list) ++ { ++ p = e_list; ++ e_list = e_list->next; ++ _asn1_remove_node (p->node, 0); ++ free (p); ++ } ++} ++ ++ ++char * ++_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]) ++{ ++ uint64_t d, r; ++ char temp[LTOSTR_MAX_SIZE]; ++ int count, k, start; ++ uint64_t val; ++ ++ if (v < 0) ++ { ++ str[0] = '-'; ++ start = 1; ++ val = -((uint64_t)v); ++ } ++ else ++ { ++ val = v; ++ start = 0; ++ } ++ ++ count = 0; ++ do ++ { ++ d = grub_divmod64(val, 10, NULL); ++ r = val - d * 10; ++ temp[start + count] = '0' + (char) r; ++ count++; ++ val = d; ++ } ++ while (val && ((start+count) < LTOSTR_MAX_SIZE-1)); ++ ++ for (k = 0; k < count; k++) ++ str[k + start] = temp[start + count - k - 1]; ++ str[count + start] = 0; ++ return str; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_change_integer_value */ ++/* Description: converts into DER coding the value assign to an */ ++/* INTEGER constant. */ ++/* Parameters: */ ++/* node: root of an ASN1element. */ ++/* Return: */ ++/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ ++/* otherwise ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_change_integer_value (asn1_node node) ++{ ++ asn1_node p; ++ unsigned char val[SIZEOF_UNSIGNED_LONG_INT]; ++ unsigned char val2[SIZEOF_UNSIGNED_LONG_INT + 1]; ++ int len; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ while (p) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_INTEGER) ++ && (p->type & CONST_ASSIGN)) ++ { ++ if (p->value) ++ { ++ _asn1_convert_integer (p->value, val, sizeof (val), &len); ++ asn1_octet_der (val, len, val2, &len); ++ _asn1_set_value (p, val2, len); ++ } ++ } ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else ++ { ++ if (p == node) ++ p = NULL; ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == node) ++ { ++ p = NULL; ++ break; ++ } ++ if (p && p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++#define MAX_CONSTANTS 1024 ++/******************************************************************/ ++/* Function : _asn1_expand_object_id */ ++/* Description: expand the IDs of an OBJECT IDENTIFIER constant. */ ++/* Parameters: */ ++/* list: root of an object list */ ++/* node: root of an ASN1 element. */ ++/* Return: */ ++/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ ++/* otherwise ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_expand_object_id (list_type **list, asn1_node node) ++{ ++ asn1_node p, p2, p3, p4, p5; ++ char name_root[ASN1_MAX_NAME_SIZE], name2[2 * ASN1_MAX_NAME_SIZE + 1]; ++ int move, tlen, tries; ++ unsigned max_constants; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ _asn1_str_cpy (name_root, sizeof (name_root), node->name); ++ ++ p = node; ++ move = DOWN; ++ tries = 0; ++ ++ while (!((p == node) && (move == UP))) ++ { ++ if (move != UP) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) ++ && (p->type & CONST_ASSIGN)) ++ { ++ p2 = p->down; ++ if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT)) ++ { ++ if (p2->value && !c_isdigit (p2->value[0])) ++ { ++ _asn1_str_cpy (name2, sizeof (name2), name_root); ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); ++ p3 = asn1_find_node (node, name2); ++ if (!p3 || _asn1_is_up(p2, p3) || ++ (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) || ++ !(p3->type & CONST_ASSIGN)) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ _asn1_set_down (p, p2->right); ++ if (p2->down) ++ _asn1_delete_structure (*list, &p2->down, 0); ++ _asn1_delete_node_from_list(*list, p2); ++ _asn1_remove_node (p2, 0); ++ p2 = p; ++ p4 = p3->down; ++ max_constants = 0; ++ while (p4) ++ { ++ if (type_field (p4->type) == ASN1_ETYPE_CONSTANT) ++ { ++ max_constants++; ++ if (max_constants == MAX_CONSTANTS) ++ return ASN1_RECURSION; ++ ++ p5 = ++ _asn1_add_single_node (ASN1_ETYPE_CONSTANT); ++ _asn1_set_name (p5, p4->name); ++ if (p4->value) ++ { ++ tlen = _asn1_strlen (p4->value); ++ if (tlen > 0) ++ _asn1_set_value (p5, p4->value, tlen + 1); ++ } ++ _asn1_add_static_node2(list, p5); ++ ++ if (p2 == p) ++ { ++ _asn1_set_right (p5, p->down); ++ _asn1_set_down (p, p5); ++ } ++ else ++ { ++ _asn1_set_right (p5, p2->right); ++ _asn1_set_right (p2, p5); ++ } ++ p2 = p5; ++ } ++ p4 = p4->right; ++ } ++ move = DOWN; ++ ++ tries++; ++ if (tries >= EXPAND_OBJECT_ID_MAX_RECURSION) ++ return ASN1_RECURSION; ++ ++ continue; ++ } ++ } ++ } ++ move = DOWN; ++ } ++ else ++ move = RIGHT; ++ ++ tries = 0; ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ ++ if (p == node) ++ { ++ move = UP; ++ continue; ++ } ++ ++ if (move == RIGHT) ++ { ++ if (p && p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ /*******************************/ ++ /* expand DEFAULT */ ++ /*******************************/ ++ p = node; ++ move = DOWN; ++ ++ while (!((p == node) && (move == UP))) ++ { ++ if (move != UP) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p->type & CONST_DEFAULT)) ++ { ++ p2 = p->down; ++ if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT)) ++ { ++ _asn1_str_cpy (name2, sizeof (name2), name_root); ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ if (p2->value) ++ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); ++ p3 = asn1_find_node (node, name2); ++ if (!p3 || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ++ || !(p3->type & CONST_ASSIGN)) ++ return ASN1_ELEMENT_NOT_FOUND; ++ p4 = p3->down; ++ name2[0] = 0; ++ while (p4) ++ { ++ if (type_field (p4->type) == ASN1_ETYPE_CONSTANT) ++ { ++ if (p4->value == NULL) ++ return ASN1_VALUE_NOT_FOUND; ++ ++ if (name2[0]) ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ _asn1_str_cat (name2, sizeof (name2), ++ (char *) p4->value); ++ } ++ p4 = p4->right; ++ } ++ tlen = strlen (name2); ++ if (tlen > 0) ++ _asn1_set_value (p2, name2, tlen + 1); ++ } ++ } ++ move = DOWN; ++ } ++ else ++ move = RIGHT; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ ++ if (p == node) ++ { ++ move = UP; ++ continue; ++ } ++ ++ if (move == RIGHT) ++ { ++ if (p && p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_type_set_config */ ++/* Description: sets the CONST_SET and CONST_NOT_USED properties */ ++/* in the fields of the SET elements. */ ++/* Parameters: */ ++/* node: root of an ASN1 element. */ ++/* Return: */ ++/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ ++/* otherwise ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_type_set_config (asn1_node node) ++{ ++ asn1_node p, p2; ++ int move; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ move = DOWN; ++ ++ while (!((p == node) && (move == UP))) ++ { ++ if (move != UP) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_SET) ++ { ++ p2 = p->down; ++ while (p2) ++ { ++ if (type_field (p2->type) != ASN1_ETYPE_TAG) ++ p2->type |= CONST_SET | CONST_NOT_USED; ++ p2 = p2->right; ++ } ++ } ++ move = DOWN; ++ } ++ else ++ move = RIGHT; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ ++ if (p == node) ++ { ++ move = UP; ++ continue; ++ } ++ ++ if (move == RIGHT) ++ { ++ if (p && p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_check_identifier */ ++/* Description: checks the definitions of all the identifiers */ ++/* and the first element of an OBJECT_ID (e.g. {pkix 0 4}). */ ++/* The _asn1_identifierMissing global variable is filled if */ ++/* necessary. */ ++/* Parameters: */ ++/* node: root of an ASN1 element. */ ++/* Return: */ ++/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ ++/* ASN1_IDENTIFIER_NOT_FOUND if an identifier is not defined, */ ++/* otherwise ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_check_identifier (asn1_node_const node) ++{ ++ asn1_node_const p, p2; ++ char name2[ASN1_MAX_NAME_SIZE * 2 + 2]; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ while (p) ++ { ++ if (p->value && type_field (p->type) == ASN1_ETYPE_IDENTIFIER) ++ { ++ _asn1_str_cpy (name2, sizeof (name2), node->name); ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ _asn1_str_cat (name2, sizeof (name2), (char *) p->value); ++ p2 = asn1_find_node (node, name2); ++ if (p2 == NULL) ++ { ++ if (p->value) ++ _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p->value); ++ else ++ _asn1_strcpy (_asn1_identifierMissing, "(null)"); ++ return ASN1_IDENTIFIER_NOT_FOUND; ++ } ++ } ++ else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p->type & CONST_DEFAULT)) ++ { ++ p2 = p->down; ++ if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT)) ++ { ++ _asn1_str_cpy (name2, sizeof (name2), node->name); ++ if (p2->value) ++ { ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); ++ _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value); ++ } ++ else ++ _asn1_strcpy (_asn1_identifierMissing, "(null)"); ++ ++ p2 = asn1_find_node (node, name2); ++ if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) || ++ !(p2->type & CONST_ASSIGN)) ++ return ASN1_IDENTIFIER_NOT_FOUND; ++ else ++ _asn1_identifierMissing[0] = 0; ++ } ++ } ++ else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p->type & CONST_ASSIGN)) ++ { ++ p2 = p->down; ++ if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT)) ++ { ++ if (p2->value && !c_isdigit (p2->value[0])) ++ { ++ _asn1_str_cpy (name2, sizeof (name2), node->name); ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); ++ _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value); ++ ++ p2 = asn1_find_node (node, name2); ++ if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) ++ || !(p2->type & CONST_ASSIGN)) ++ return ASN1_IDENTIFIER_NOT_FOUND; ++ else ++ _asn1_identifierMissing[0] = 0; ++ } ++ } ++ } ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (p) ++ { ++ p = _asn1_find_up (p); ++ if (p == node) ++ { ++ p = NULL; ++ break; ++ } ++ if (p && p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_set_default_tag */ ++/* Description: sets the default IMPLICIT or EXPLICIT property in */ ++/* the tagged elements that don't have this declaration. */ ++/* Parameters: */ ++/* node: pointer to a DEFINITIONS element. */ ++/* Return: */ ++/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to */ ++/* a DEFINITIONS element, */ ++/* otherwise ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_set_default_tag (asn1_node node) ++{ ++ asn1_node p; ++ ++ if ((node == NULL) || (type_field (node->type) != ASN1_ETYPE_DEFINITIONS)) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ while (p) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_TAG) && ++ !(p->type & CONST_EXPLICIT) && !(p->type & CONST_IMPLICIT)) ++ { ++ if (node->type & CONST_EXPLICIT) ++ p->type |= CONST_EXPLICIT; ++ else ++ p->type |= CONST_IMPLICIT; ++ } ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == node) ++ { ++ p = NULL; ++ break; ++ } ++ if (p && p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ ++ return ASN1_SUCCESS; ++} +diff --git a/grub-core/lib/libtasn1/lib/parser_aux.h b/grub-core/lib/libtasn1/lib/parser_aux.h +new file mode 100644 +index 000000000..598e684b3 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/parser_aux.h +@@ -0,0 +1,172 @@ ++/* ++ * Copyright (C) 2000-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#ifndef _PARSER_AUX_H ++#define _PARSER_AUX_H ++ ++/***********************************************/ ++/* Type: list_type */ ++/* Description: type used in the list during */ ++/* the structure creation. */ ++/***********************************************/ ++typedef struct list_struct ++{ ++ asn1_node node; ++ struct list_struct *next; ++} list_type; ++ ++/***************************************/ ++/* Functions used by ASN.1 parser */ ++/***************************************/ ++asn1_node _asn1_add_static_node (list_type **e_list, unsigned int type); ++ ++void _asn1_delete_list (list_type *e_list); ++ ++void _asn1_delete_list_and_nodes (list_type *e_list); ++ ++void _asn1_delete_node_from_list (list_type *list, asn1_node node); ++ ++asn1_node ++_asn1_set_value (asn1_node node, const void *value, unsigned int len); ++ ++asn1_node _asn1_set_value_m (asn1_node node, void *value, unsigned int len); ++ ++asn1_node ++_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len); ++ ++asn1_node ++_asn1_append_value (asn1_node node, const void *value, unsigned int len); ++ ++asn1_node _asn1_set_name (asn1_node node, const char *name); ++ ++asn1_node _asn1_cpy_name (asn1_node dst, asn1_node_const src); ++ ++asn1_node _asn1_set_right (asn1_node node, asn1_node right); ++ ++asn1_node _asn1_get_last_right (asn1_node_const node); ++ ++void _asn1_remove_node (asn1_node node, unsigned int flags); ++ ++/* Max 64-bit integer length is 20 chars + 1 for sign + 1 for null termination */ ++#define LTOSTR_MAX_SIZE 22 ++char *_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]); ++ ++asn1_node _asn1_find_up (asn1_node_const node); ++ ++int _asn1_change_integer_value (asn1_node node); ++ ++#define EXPAND_OBJECT_ID_MAX_RECURSION 16 ++int _asn1_expand_object_id (list_type **list, asn1_node node); ++ ++int _asn1_type_set_config (asn1_node node); ++ ++int _asn1_check_identifier (asn1_node_const node); ++ ++int _asn1_set_default_tag (asn1_node node); ++ ++/******************************************************************/ ++/* Function : _asn1_get_right */ ++/* Description: returns the element pointed by the RIGHT field of */ ++/* a NODE_ASN element. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* Return: field RIGHT of NODE. */ ++/******************************************************************/ ++inline static asn1_node ++_asn1_get_right (asn1_node_const node) ++{ ++ if (node == NULL) ++ return NULL; ++ return node->right; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_set_down */ ++/* Description: sets the field DOWN in a NODE_ASN element. */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* down: pointer to a NODE_ASN element that you want be pointed */ ++/* by NODE. */ ++/* Return: pointer to *NODE. */ ++/******************************************************************/ ++inline static asn1_node ++_asn1_set_down (asn1_node node, asn1_node down) ++{ ++ if (node == NULL) ++ return node; ++ node->down = down; ++ if (down) ++ down->left = node; ++ return node; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_get_down */ ++/* Description: returns the element pointed by the DOWN field of */ ++/* a NODE_ASN element. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* Return: field DOWN of NODE. */ ++/******************************************************************/ ++inline static asn1_node ++_asn1_get_down (asn1_node_const node) ++{ ++ if (node == NULL) ++ return NULL; ++ return node->down; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_get_name */ ++/* Description: returns the name of a NODE_ASN element. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* Return: a null terminated string. */ ++/******************************************************************/ ++inline static char * ++_asn1_get_name (asn1_node_const node) ++{ ++ if (node == NULL) ++ return NULL; ++ return (char *) node->name; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_mod_type */ ++/* Description: change the field TYPE of an NODE_ASN element. */ ++/* The new value is the old one | (bitwise or) the */ ++/* paramener VALUE. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* value: the integer value that must be or-ed with the current */ ++/* value of field TYPE. */ ++/* Return: NODE pointer. */ ++/******************************************************************/ ++inline static asn1_node ++_asn1_mod_type (asn1_node node, unsigned int value) ++{ ++ if (node == NULL) ++ return node; ++ node->type |= value; ++ return node; ++} ++ ++#endif +diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c +new file mode 100644 +index 000000000..fcfde01a3 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/structure.c +@@ -0,0 +1,1222 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++ ++/*****************************************************/ ++/* File: structure.c */ ++/* Description: Functions to create and delete an */ ++/* ASN1 tree. */ ++/*****************************************************/ ++ ++ ++#include ++#include ++#include "parser_aux.h" ++#include ++ ++ ++extern char _asn1_identifierMissing[]; ++ ++ ++/******************************************************/ ++/* Function : _asn1_add_single_node */ ++/* Description: creates a new NODE_ASN element. */ ++/* Parameters: */ ++/* type: type of the new element (see ASN1_ETYPE_ */ ++/* and CONST_ constants). */ ++/* Return: pointer to the new element. */ ++/******************************************************/ ++asn1_node ++_asn1_add_single_node (unsigned int type) ++{ ++ asn1_node punt; ++ ++ punt = calloc (1, sizeof (struct asn1_node_st)); ++ if (punt == NULL) ++ return NULL; ++ ++ punt->type = type; ++ ++ return punt; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_find_left */ ++/* Description: returns the NODE_ASN element with RIGHT field that*/ ++/* points the element NODE. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* Return: NULL if not found. */ ++/******************************************************************/ ++asn1_node ++_asn1_find_left (asn1_node_const node) ++{ ++ if ((node == NULL) || (node->left == NULL) || (node->left->down == node)) ++ return NULL; ++ ++ return node->left; ++} ++ ++#if 0 ++int ++_asn1_create_static_structure (asn1_node_const pointer, char *output_file_name, ++ char *vector_name) ++{ ++ FILE *file; ++ asn1_node_const p; ++ unsigned long t; ++ ++ file = fopen (output_file_name, "w"); ++ ++ if (file == NULL) ++ return ASN1_FILE_NOT_FOUND; ++ ++ fprintf (file, "#if HAVE_CONFIG_H\n"); ++ fprintf (file, "# include \"config.h\"\n"); ++ fprintf (file, "#endif\n\n"); ++ ++ fprintf (file, "#include \n\n"); ++ ++ fprintf (file, "const asn1_static_node %s[] = {\n", vector_name); ++ ++ p = pointer; ++ ++ while (p) ++ { ++ fprintf (file, " { "); ++ ++ if (p->name[0] != 0) ++ fprintf (file, "\"%s\", ", p->name); ++ else ++ fprintf (file, "NULL, "); ++ ++ t = p->type; ++ if (p->down) ++ t |= CONST_DOWN; ++ if (p->right) ++ t |= CONST_RIGHT; ++ ++ fprintf (file, "%lu, ", t); ++ ++ if (p->value) ++ fprintf (file, "\"%s\"},\n", p->value); ++ else ++ fprintf (file, "NULL },\n"); ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else if (p->right) ++ { ++ p = p->right; ++ } ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == pointer) ++ { ++ p = NULL; ++ break; ++ } ++ if (p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ ++ fprintf (file, " { NULL, 0, NULL }\n};\n"); ++ ++ fclose (file); ++ ++ return ASN1_SUCCESS; ++} ++#endif ++ ++/** ++ * asn1_array2tree: ++ * @array: specify the array that contains ASN.1 declarations ++ * @definitions: return the pointer to the structure created by ++ * *ARRAY ASN.1 declarations ++ * @errorDescription: return the error description. ++ * ++ * Creates the structures needed to manage the ASN.1 definitions. ++ * @array is a vector created by asn1_parser2array(). ++ * ++ * Returns: %ASN1_SUCCESS if structure was created correctly, ++ * %ASN1_ELEMENT_NOT_EMPTY if *@definitions not NULL, ++ * %ASN1_IDENTIFIER_NOT_FOUND if in the file there is an identifier ++ * that is not defined (see @errorDescription for more information), ++ * %ASN1_ARRAY_ERROR if the array pointed by @array is wrong. ++ **/ ++int ++asn1_array2tree (const asn1_static_node * array, asn1_node * definitions, ++ char *errorDescription) ++{ ++ asn1_node p, p_last = NULL; ++ unsigned long k; ++ int move; ++ int result; ++ unsigned int type; ++ list_type *e_list = NULL; ++ ++ if (errorDescription) ++ errorDescription[0] = 0; ++ ++ if (*definitions != NULL) ++ return ASN1_ELEMENT_NOT_EMPTY; ++ ++ move = UP; ++ ++ for (k = 0; array[k].value || array[k].type || array[k].name; k++) ++ { ++ type = convert_old_type (array[k].type); ++ ++ p = _asn1_add_static_node (&e_list, type & (~CONST_DOWN)); ++ if (array[k].name) ++ _asn1_set_name (p, array[k].name); ++ if (array[k].value) ++ _asn1_set_value (p, array[k].value, strlen (array[k].value) + 1); ++ ++ if (*definitions == NULL) ++ *definitions = p; ++ ++ if (move == DOWN) ++ { ++ if (p_last && p_last->down) ++ _asn1_delete_structure (e_list, &p_last->down, 0); ++ _asn1_set_down (p_last, p); ++ } ++ else if (move == RIGHT) ++ { ++ if (p_last && p_last->right) ++ _asn1_delete_structure (e_list, &p_last->right, 0); ++ _asn1_set_right (p_last, p); ++ } ++ ++ p_last = p; ++ ++ if (type & CONST_DOWN) ++ move = DOWN; ++ else if (type & CONST_RIGHT) ++ move = RIGHT; ++ else ++ { ++ while (p_last != *definitions) ++ { ++ p_last = _asn1_find_up (p_last); ++ ++ if (p_last == NULL) ++ break; ++ ++ if (p_last->type & CONST_RIGHT) ++ { ++ p_last->type &= ~CONST_RIGHT; ++ move = RIGHT; ++ break; ++ } ++ } /* while */ ++ } ++ } /* while */ ++ ++ if (p_last == *definitions) ++ { ++ result = _asn1_check_identifier (*definitions); ++ if (result == ASN1_SUCCESS) ++ { ++ _asn1_change_integer_value (*definitions); ++ result = _asn1_expand_object_id (&e_list, *definitions); ++ } ++ } ++ else ++ { ++ result = ASN1_ARRAY_ERROR; ++ } ++ ++ if (errorDescription != NULL) ++ { ++ if (result == ASN1_IDENTIFIER_NOT_FOUND) ++ { ++ Estrcpy (errorDescription, ":: identifier '"); ++ Estrcat (errorDescription, _asn1_identifierMissing); ++ Estrcat (errorDescription, "' not found"); ++ } ++ else ++ errorDescription[0] = 0; ++ } ++ ++ if (result != ASN1_SUCCESS) ++ { ++ _asn1_delete_list_and_nodes (e_list); ++ *definitions = NULL; ++ } ++ else ++ _asn1_delete_list (e_list); ++ ++ return result; ++} ++ ++/** ++ * asn1_delete_structure: ++ * @structure: pointer to the structure that you want to delete. ++ * ++ * Deletes the structure *@structure. At the end, *@structure is set ++ * to NULL. ++ * ++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if ++ * *@structure was NULL. ++ **/ ++int ++asn1_delete_structure (asn1_node * structure) ++{ ++ return _asn1_delete_structure (NULL, structure, 0); ++} ++ ++/** ++ * asn1_delete_structure2: ++ * @structure: pointer to the structure that you want to delete. ++ * @flags: additional flags (see %ASN1_DELETE_FLAG) ++ * ++ * Deletes the structure *@structure. At the end, *@structure is set ++ * to NULL. ++ * ++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if ++ * *@structure was NULL. ++ **/ ++int ++asn1_delete_structure2 (asn1_node * structure, unsigned int flags) ++{ ++ return _asn1_delete_structure (NULL, structure, flags); ++} ++ ++int ++_asn1_delete_structure (list_type *e_list, asn1_node * structure, unsigned int flags) ++{ ++ asn1_node p, p2, p3; ++ ++ if (*structure == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = *structure; ++ while (p) ++ { ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else ++ { /* no down */ ++ p2 = p->right; ++ if (p != *structure) ++ { ++ p3 = _asn1_find_up (p); ++ _asn1_set_down (p3, p2); ++ if (e_list) ++ _asn1_delete_node_from_list (e_list, p); ++ _asn1_remove_node (p, flags); ++ p = p3; ++ } ++ else ++ { /* p==root */ ++ p3 = _asn1_find_left (p); ++ if (!p3) ++ { ++ p3 = _asn1_find_up (p); ++ if (p3) ++ _asn1_set_down (p3, p2); ++ else ++ { ++ if (p->right) ++ p->right->left = NULL; ++ } ++ } ++ else ++ _asn1_set_right (p3, p2); ++ if (e_list) ++ _asn1_delete_node_from_list (e_list, p); ++ _asn1_remove_node (p, flags); ++ p = NULL; ++ } ++ } ++ } ++ ++ *structure = NULL; ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_delete_element: ++ * @structure: pointer to the structure that contains the element you ++ * want to delete. ++ * @element_name: element's name you want to delete. ++ * ++ * Deletes the element named *@element_name inside *@structure. ++ * ++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if ++ * the @element_name was not found. ++ **/ ++int ++asn1_delete_element (asn1_node structure, const char *element_name) ++{ ++ asn1_node p2, p3, source_node; ++ ++ source_node = asn1_find_node (structure, element_name); ++ ++ if (source_node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p2 = source_node->right; ++ p3 = _asn1_find_left (source_node); ++ if (!p3) ++ { ++ p3 = _asn1_find_up (source_node); ++ if (p3) ++ _asn1_set_down (p3, p2); ++ else if (source_node->right) ++ source_node->right->left = NULL; ++ } ++ else ++ _asn1_set_right (p3, p2); ++ ++ return asn1_delete_structure (&source_node); ++} ++ ++#ifndef __clang_analyzer__ ++asn1_node ++_asn1_copy_structure3 (asn1_node_const source_node) ++{ ++ asn1_node_const p_s; ++ asn1_node dest_node, p_d, p_d_prev; ++ int move; ++ ++ if (source_node == NULL) ++ return NULL; ++ ++ dest_node = _asn1_add_single_node (source_node->type); ++ ++ p_s = source_node; ++ p_d = dest_node; ++ ++ move = DOWN; ++ ++ do ++ { ++ if (move != UP) ++ { ++ if (p_s->name[0] != 0) ++ _asn1_cpy_name (p_d, p_s); ++ if (p_s->value) ++ _asn1_set_value (p_d, p_s->value, p_s->value_len); ++ if (p_s->down) ++ { ++ p_s = p_s->down; ++ p_d_prev = p_d; ++ p_d = _asn1_add_single_node (p_s->type); ++ _asn1_set_down (p_d_prev, p_d); ++ continue; ++ } ++ p_d->start = p_s->start; ++ p_d->end = p_s->end; ++ } ++ ++ if (p_s == source_node) ++ break; ++ ++ if (p_s->right) ++ { ++ move = RIGHT; ++ p_s = p_s->right; ++ p_d_prev = p_d; ++ p_d = _asn1_add_single_node (p_s->type); ++ _asn1_set_right (p_d_prev, p_d); ++ } ++ else ++ { ++ move = UP; ++ p_s = _asn1_find_up (p_s); ++ p_d = _asn1_find_up (p_d); ++ } ++ } ++ while (p_s != source_node); ++ return dest_node; ++} ++#else ++ ++/* Non-production code */ ++asn1_node ++_asn1_copy_structure3 (asn1_node_const source_node) ++{ ++ return NULL; ++} ++#endif /* __clang_analyzer__ */ ++ ++ ++static asn1_node ++_asn1_copy_structure2 (asn1_node_const root, const char *source_name) ++{ ++ asn1_node source_node; ++ ++ source_node = asn1_find_node (root, source_name); ++ ++ return _asn1_copy_structure3 (source_node); ++ ++} ++ ++ ++static int ++_asn1_type_choice_config (asn1_node node) ++{ ++ asn1_node p, p2, p3, p4; ++ int move, tlen; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ move = DOWN; ++ ++ while (!((p == node) && (move == UP))) ++ { ++ if (move != UP) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_CHOICE) ++ && (p->type & CONST_TAG)) ++ { ++ p2 = p->down; ++ while (p2) ++ { ++ if (type_field (p2->type) != ASN1_ETYPE_TAG) ++ { ++ p2->type |= CONST_TAG; ++ p3 = _asn1_find_left (p2); ++ while (p3) ++ { ++ if (type_field (p3->type) == ASN1_ETYPE_TAG) ++ { ++ p4 = _asn1_add_single_node (p3->type); ++ tlen = _asn1_strlen (p3->value); ++ if (tlen > 0) ++ _asn1_set_value (p4, p3->value, tlen + 1); ++ _asn1_set_right (p4, p2->down); ++ _asn1_set_down (p2, p4); ++ } ++ p3 = _asn1_find_left (p3); ++ } ++ } ++ p2 = p2->right; ++ } ++ p->type &= ~(CONST_TAG); ++ p2 = p->down; ++ while (p2) ++ { ++ p3 = p2->right; ++ if (type_field (p2->type) == ASN1_ETYPE_TAG) ++ asn1_delete_structure (&p2); ++ p2 = p3; ++ } ++ } ++ move = DOWN; ++ } ++ else ++ move = RIGHT; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ ++ if (p == node) ++ { ++ move = UP; ++ continue; ++ } ++ ++ if (move == RIGHT) ++ { ++ if (p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++static int ++_asn1_expand_identifier (asn1_node * node, asn1_node_const root) ++{ ++ asn1_node p, p2, p3; ++ char name2[ASN1_MAX_NAME_SIZE + 2]; ++ int move; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = *node; ++ move = DOWN; ++ ++ while (!((p == *node) && (move == UP))) ++ { ++ if (move != UP) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_IDENTIFIER) ++ { ++ snprintf (name2, sizeof (name2), "%s.%s", root->name, p->value); ++ p2 = _asn1_copy_structure2 (root, name2); ++ if (p2 == NULL) ++ { ++ return ASN1_IDENTIFIER_NOT_FOUND; ++ } ++ _asn1_cpy_name (p2, p); ++ p2->right = p->right; ++ p2->left = p->left; ++ if (p->right) ++ p->right->left = p2; ++ p3 = p->down; ++ if (p3) ++ { ++ while (p3->right) ++ p3 = p3->right; ++ _asn1_set_right (p3, p2->down); ++ _asn1_set_down (p2, p->down); ++ } ++ ++ p3 = _asn1_find_left (p); ++ if (p3) ++ _asn1_set_right (p3, p2); ++ else ++ { ++ p3 = _asn1_find_up (p); ++ if (p3) ++ _asn1_set_down (p3, p2); ++ else ++ { ++ p2->left = NULL; ++ } ++ } ++ ++ if (p->type & CONST_SIZE) ++ p2->type |= CONST_SIZE; ++ if (p->type & CONST_TAG) ++ p2->type |= CONST_TAG; ++ if (p->type & CONST_OPTION) ++ p2->type |= CONST_OPTION; ++ if (p->type & CONST_DEFAULT) ++ p2->type |= CONST_DEFAULT; ++ if (p->type & CONST_SET) ++ p2->type |= CONST_SET; ++ if (p->type & CONST_NOT_USED) ++ p2->type |= CONST_NOT_USED; ++ ++ if (p == *node) ++ *node = p2; ++ _asn1_remove_node (p, 0); ++ p = p2; ++ move = DOWN; ++ continue; ++ } ++ move = DOWN; ++ } ++ else ++ move = RIGHT; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ ++ if (p == *node) ++ { ++ move = UP; ++ continue; ++ } ++ ++ if (move == RIGHT) ++ { ++ if (p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_create_element: ++ * @definitions: pointer to the structure returned by "parser_asn1" function ++ * @source_name: the name of the type of the new structure (must be ++ * inside p_structure). ++ * @element: pointer to the structure created. ++ * ++ * Creates a structure of type @source_name. Example using ++ * "pkix.asn": ++ * ++ * rc = asn1_create_element(cert_def, "PKIX1.Certificate", certptr); ++ * ++ * Returns: %ASN1_SUCCESS if creation OK, %ASN1_ELEMENT_NOT_FOUND if ++ * @source_name is not known. ++ **/ ++int ++asn1_create_element (asn1_node_const definitions, const char *source_name, ++ asn1_node * element) ++{ ++ asn1_node dest_node; ++ int res; ++ ++ dest_node = _asn1_copy_structure2 (definitions, source_name); ++ ++ if (dest_node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ _asn1_set_name (dest_node, ""); ++ ++ res = _asn1_expand_identifier (&dest_node, definitions); ++ _asn1_type_choice_config (dest_node); ++ ++ *element = dest_node; ++ ++ return res; ++} ++ ++#if 0 ++/** ++ * asn1_print_structure: ++ * @out: pointer to the output file (e.g. stdout). ++ * @structure: pointer to the structure that you want to visit. ++ * @name: an element of the structure ++ * @mode: specify how much of the structure to print, can be ++ * %ASN1_PRINT_NAME, %ASN1_PRINT_NAME_TYPE, ++ * %ASN1_PRINT_NAME_TYPE_VALUE, or %ASN1_PRINT_ALL. ++ * ++ * Prints on the @out file descriptor the structure's tree starting ++ * from the @name element inside the structure @structure. ++ **/ ++void ++asn1_print_structure (FILE * out, asn1_node_const structure, const char *name, ++ int mode) ++{ ++ asn1_node_const p, root; ++ int k, indent = 0, len, len2, len3; ++ ++ if (out == NULL) ++ return; ++ ++ root = asn1_find_node (structure, name); ++ ++ if (root == NULL) ++ return; ++ ++ p = root; ++ while (p) ++ { ++ if (mode == ASN1_PRINT_ALL) ++ { ++ for (k = 0; k < indent; k++) ++ fprintf (out, " "); ++ fprintf (out, "name:"); ++ if (p->name[0] != 0) ++ fprintf (out, "%s ", p->name); ++ else ++ fprintf (out, "NULL "); ++ } ++ else ++ { ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_CONSTANT: ++ case ASN1_ETYPE_TAG: ++ case ASN1_ETYPE_SIZE: ++ break; ++ default: ++ for (k = 0; k < indent; k++) ++ fprintf (out, " "); ++ fprintf (out, "name:"); ++ if (p->name[0] != 0) ++ fprintf (out, "%s ", p->name); ++ else ++ fprintf (out, "NULL "); ++ } ++ } ++ ++ if (mode != ASN1_PRINT_NAME) ++ { ++ unsigned type = type_field (p->type); ++ switch (type) ++ { ++ case ASN1_ETYPE_CONSTANT: ++ if (mode == ASN1_PRINT_ALL) ++ fprintf (out, "type:CONST"); ++ break; ++ case ASN1_ETYPE_TAG: ++ if (mode == ASN1_PRINT_ALL) ++ fprintf (out, "type:TAG"); ++ break; ++ case ASN1_ETYPE_SIZE: ++ if (mode == ASN1_PRINT_ALL) ++ fprintf (out, "type:SIZE"); ++ break; ++ case ASN1_ETYPE_DEFAULT: ++ fprintf (out, "type:DEFAULT"); ++ break; ++ case ASN1_ETYPE_IDENTIFIER: ++ fprintf (out, "type:IDENTIFIER"); ++ break; ++ case ASN1_ETYPE_ANY: ++ fprintf (out, "type:ANY"); ++ break; ++ case ASN1_ETYPE_CHOICE: ++ fprintf (out, "type:CHOICE"); ++ break; ++ case ASN1_ETYPE_DEFINITIONS: ++ fprintf (out, "type:DEFINITIONS"); ++ break; ++ CASE_HANDLED_ETYPES: ++ fprintf (out, "%s", _asn1_tags[type].desc); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ if ((mode == ASN1_PRINT_NAME_TYPE_VALUE) || (mode == ASN1_PRINT_ALL)) ++ { ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_CONSTANT: ++ if (mode == ASN1_PRINT_ALL) ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ break; ++ case ASN1_ETYPE_TAG: ++ if (mode == ASN1_PRINT_ALL) ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ break; ++ case ASN1_ETYPE_SIZE: ++ if (mode == ASN1_PRINT_ALL) ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ break; ++ case ASN1_ETYPE_DEFAULT: ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ else if (p->type & CONST_TRUE) ++ fprintf (out, " value:TRUE"); ++ else if (p->type & CONST_FALSE) ++ fprintf (out, " value:FALSE"); ++ break; ++ case ASN1_ETYPE_IDENTIFIER: ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ break; ++ case ASN1_ETYPE_INTEGER: ++ if (p->value) ++ { ++ len2 = -1; ++ len = asn1_get_length_der (p->value, p->value_len, &len2); ++ fprintf (out, " value:0x"); ++ if (len > 0) ++ for (k = 0; k < len; k++) ++ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); ++ } ++ break; ++ case ASN1_ETYPE_ENUMERATED: ++ if (p->value) ++ { ++ len2 = -1; ++ len = asn1_get_length_der (p->value, p->value_len, &len2); ++ fprintf (out, " value:0x"); ++ if (len > 0) ++ for (k = 0; k < len; k++) ++ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); ++ } ++ break; ++ case ASN1_ETYPE_BOOLEAN: ++ if (p->value) ++ { ++ if (p->value[0] == 'T') ++ fprintf (out, " value:TRUE"); ++ else if (p->value[0] == 'F') ++ fprintf (out, " value:FALSE"); ++ } ++ break; ++ case ASN1_ETYPE_BIT_STRING: ++ if (p->value) ++ { ++ len2 = -1; ++ len = asn1_get_length_der (p->value, p->value_len, &len2); ++ if (len > 0) ++ { ++ fprintf (out, " value(%i):", ++ (len - 1) * 8 - (p->value[len2])); ++ for (k = 1; k < len; k++) ++ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); ++ } ++ } ++ break; ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ case ASN1_ETYPE_UTC_TIME: ++ if (p->value) ++ { ++ fprintf (out, " value:"); ++ for (k = 0; k < p->value_len; k++) ++ fprintf (out, "%c", (p->value)[k]); ++ } ++ break; ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ if (p->value) ++ { ++ len2 = -1; ++ len = asn1_get_length_der (p->value, p->value_len, &len2); ++ fprintf (out, " value:"); ++ if (len > 0) ++ for (k = 0; k < len; k++) ++ fprintf (out, "%c", (p->value)[k + len2]); ++ } ++ break; ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_OCTET_STRING: ++ if (p->value) ++ { ++ len2 = -1; ++ len = asn1_get_length_der (p->value, p->value_len, &len2); ++ fprintf (out, " value:"); ++ if (len > 0) ++ for (k = 0; k < len; k++) ++ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); ++ } ++ break; ++ case ASN1_ETYPE_OBJECT_ID: ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ break; ++ case ASN1_ETYPE_ANY: ++ if (p->value) ++ { ++ len3 = -1; ++ len2 = asn1_get_length_der (p->value, p->value_len, &len3); ++ fprintf (out, " value:"); ++ if (len2 > 0) ++ for (k = 0; k < len2; k++) ++ fprintf (out, "%02x", (unsigned) (p->value)[k + len3]); ++ } ++ break; ++ case ASN1_ETYPE_SET: ++ case ASN1_ETYPE_SET_OF: ++ case ASN1_ETYPE_CHOICE: ++ case ASN1_ETYPE_DEFINITIONS: ++ case ASN1_ETYPE_SEQUENCE_OF: ++ case ASN1_ETYPE_SEQUENCE: ++ case ASN1_ETYPE_NULL: ++ break; ++ default: ++ break; ++ } ++ } ++ ++ if (mode == ASN1_PRINT_ALL) ++ { ++ if (p->type & 0x1FFFFF00) ++ { ++ fprintf (out, " attr:"); ++ if (p->type & CONST_UNIVERSAL) ++ fprintf (out, "UNIVERSAL,"); ++ if (p->type & CONST_PRIVATE) ++ fprintf (out, "PRIVATE,"); ++ if (p->type & CONST_APPLICATION) ++ fprintf (out, "APPLICATION,"); ++ if (p->type & CONST_EXPLICIT) ++ fprintf (out, "EXPLICIT,"); ++ if (p->type & CONST_IMPLICIT) ++ fprintf (out, "IMPLICIT,"); ++ if (p->type & CONST_TAG) ++ fprintf (out, "TAG,"); ++ if (p->type & CONST_DEFAULT) ++ fprintf (out, "DEFAULT,"); ++ if (p->type & CONST_TRUE) ++ fprintf (out, "TRUE,"); ++ if (p->type & CONST_FALSE) ++ fprintf (out, "FALSE,"); ++ if (p->type & CONST_LIST) ++ fprintf (out, "LIST,"); ++ if (p->type & CONST_MIN_MAX) ++ fprintf (out, "MIN_MAX,"); ++ if (p->type & CONST_OPTION) ++ fprintf (out, "OPTION,"); ++ if (p->type & CONST_1_PARAM) ++ fprintf (out, "1_PARAM,"); ++ if (p->type & CONST_SIZE) ++ fprintf (out, "SIZE,"); ++ if (p->type & CONST_DEFINED_BY) ++ fprintf (out, "DEF_BY,"); ++ if (p->type & CONST_GENERALIZED) ++ fprintf (out, "GENERALIZED,"); ++ if (p->type & CONST_UTC) ++ fprintf (out, "UTC,"); ++ if (p->type & CONST_SET) ++ fprintf (out, "SET,"); ++ if (p->type & CONST_NOT_USED) ++ fprintf (out, "NOT_USED,"); ++ if (p->type & CONST_ASSIGN) ++ fprintf (out, "ASSIGNMENT,"); ++ } ++ } ++ ++ if (mode == ASN1_PRINT_ALL) ++ { ++ fprintf (out, "\n"); ++ } ++ else ++ { ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_CONSTANT: ++ case ASN1_ETYPE_TAG: ++ case ASN1_ETYPE_SIZE: ++ break; ++ default: ++ fprintf (out, "\n"); ++ } ++ } ++ ++ if (p->down) ++ { ++ p = p->down; ++ indent += 2; ++ } ++ else if (p == root) ++ { ++ p = NULL; ++ break; ++ } ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == root) ++ { ++ p = NULL; ++ break; ++ } ++ indent -= 2; ++ if (p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++} ++#endif ++ ++ ++/** ++ * asn1_number_of_elements: ++ * @element: pointer to the root of an ASN1 structure. ++ * @name: the name of a sub-structure of ROOT. ++ * @num: pointer to an integer where the result will be stored ++ * ++ * Counts the number of elements of a sub-structure called NAME with ++ * names equal to "?1","?2", ... ++ * ++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if ++ * @name is not known, %ASN1_GENERIC_ERROR if pointer @num is %NULL. ++ **/ ++int ++asn1_number_of_elements (asn1_node_const element, const char *name, int *num) ++{ ++ asn1_node_const node, p; ++ ++ if (num == NULL) ++ return ASN1_GENERIC_ERROR; ++ ++ *num = 0; ++ ++ node = asn1_find_node (element, name); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node->down; ++ ++ while (p) ++ { ++ if (p->name[0] == '?') ++ (*num)++; ++ p = p->right; ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_find_structure_from_oid: ++ * @definitions: ASN1 definitions ++ * @oidValue: value of the OID to search (e.g. "1.2.3.4"). ++ * ++ * Search the structure that is defined just after an OID definition. ++ * ++ * Returns: %NULL when @oidValue not found, otherwise the pointer to a ++ * constant string that contains the element name defined just after ++ * the OID. ++ **/ ++const char * ++asn1_find_structure_from_oid (asn1_node_const definitions, const char *oidValue) ++{ ++ char name[2 * ASN1_MAX_NAME_SIZE + 2]; ++ char value[ASN1_MAX_NAME_SIZE]; ++ asn1_node p; ++ int len; ++ int result; ++ const char *definitionsName; ++ ++ if ((definitions == NULL) || (oidValue == NULL)) ++ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ ++ ++ definitionsName = definitions->name; ++ ++ /* search the OBJECT_ID into definitions */ ++ p = definitions->down; ++ while (p) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p->type & CONST_ASSIGN)) ++ { ++ snprintf(name, sizeof(name), "%s.%s", definitionsName, p->name); ++ ++ len = ASN1_MAX_NAME_SIZE; ++ result = asn1_read_value (definitions, name, value, &len); ++ ++ if ((result == ASN1_SUCCESS) && (!strcmp (oidValue, value))) ++ { ++ p = p->right; ++ if (p == NULL) /* reach the end of ASN1 definitions */ ++ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ ++ ++ return p->name; ++ } ++ } ++ p = p->right; ++ } ++ ++ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ ++} ++ ++#if 0 ++/** ++ * asn1_copy_node: ++ * @dst: Destination asn1 node. ++ * @dst_name: Field name in destination node. ++ * @src: Source asn1 node. ++ * @src_name: Field name in source node. ++ * ++ * Create a deep copy of a asn1_node variable. That ++ * function requires @dst to be expanded using asn1_create_element(). ++ * ++ * Returns: Return %ASN1_SUCCESS on success. ++ **/ ++int ++asn1_copy_node (asn1_node dst, const char *dst_name, ++ asn1_node_const src, const char *src_name) ++{ ++ int result; ++ asn1_node dst_node; ++ void *data = NULL; ++ int size = 0; ++ ++ result = asn1_der_coding (src, src_name, NULL, &size, NULL); ++ if (result != ASN1_MEM_ERROR) ++ return result; ++ ++ data = malloc (size); ++ if (data == NULL) ++ return ASN1_MEM_ERROR; ++ ++ result = asn1_der_coding (src, src_name, data, &size, NULL); ++ if (result != ASN1_SUCCESS) ++ { ++ free (data); ++ return result; ++ } ++ ++ dst_node = asn1_find_node (dst, dst_name); ++ if (dst_node == NULL) ++ { ++ free (data); ++ return ASN1_ELEMENT_NOT_FOUND; ++ } ++ ++ result = asn1_der_decoding (&dst_node, data, size, NULL); ++ ++ free (data); ++ ++ return result; ++} ++#endif ++ ++/** ++ * asn1_dup_node: ++ * @src: Source asn1 node. ++ * @src_name: Field name in source node. ++ * ++ * Create a deep copy of a asn1_node variable. This function ++ * will return an exact copy of the provided structure. ++ * ++ * Returns: Return %NULL on failure. ++ **/ ++asn1_node ++asn1_dup_node (asn1_node_const src, const char *src_name) ++{ ++ return _asn1_copy_structure2(src, src_name); ++} +diff --git a/grub-core/lib/libtasn1/lib/structure.h b/grub-core/lib/libtasn1/lib/structure.h +new file mode 100644 +index 000000000..99e685da0 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/structure.h +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++/*************************************************/ ++/* File: structure.h */ ++/* Description: list of exported object by */ ++/* "structure.c" */ ++/*************************************************/ ++ ++#ifndef _STRUCTURE_H ++#define _STRUCTURE_H ++ ++#include "parser_aux.h" // list_type ++ ++int _asn1_create_static_structure (asn1_node_const pointer, ++ char *output_file_name, char *vector_name); ++ ++asn1_node _asn1_copy_structure3 (asn1_node_const source_node); ++ ++asn1_node _asn1_add_single_node (unsigned int type); ++ ++asn1_node _asn1_find_left (asn1_node_const node); ++ ++int ++_asn1_delete_structure (list_type *e_list, asn1_node *structure, unsigned int flags); ++ ++#endif +diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h +new file mode 100644 +index 000000000..1e7d3d64f +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h +@@ -0,0 +1,32 @@ ++#if HAVE_CONFIG_H ++# include "config.h" ++#endif ++ ++#include ++ ++const asn1_static_node CVE_2018_1000654_1_asn1_tab[] = { ++ { "TEST_TREE", 536875024, NULL }, ++ { NULL, 1610612748, NULL }, ++ { "iso", 1073741825, "1"}, ++ { "identified-organization", 1073741825, "3"}, ++ { "dod", 1073741825, "6"}, ++ { "internet", 1073741825, "1"}, ++ { "security", 1073741825, "5"}, ++ { "mechanisms", 1073741825, "5"}, ++ { "pkix", 1073741825, "7"}, ++ { "id-mod", 1073741825, "0"}, ++ { "id-pkix1-implicit-88", 1, "2"}, ++ { "id-xnyTest", 1879048204, NULL }, ++ { NULL, 1073741825, "id-ix"}, ++ { NULL, 1073741825, "29"}, ++ { NULL, 1, "1"}, ++ { "id-ix", 1880096780, "OBJECR"}, ++ { NULL, 1073741825, "id-ix"}, ++ { NULL, 1073741825, "29"}, ++ { NULL, 1, "2"}, ++ { "id-xnyTest", 805306380, NULL }, ++ { NULL, 1073741825, "id-ix"}, ++ { NULL, 1073741825, "29"}, ++ { NULL, 1, "1"}, ++ { NULL, 0, NULL } ++}; +diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h +new file mode 100644 +index 000000000..e2561e5ec +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h +@@ -0,0 +1,36 @@ ++#if HAVE_CONFIG_H ++# include "config.h" ++#endif ++ ++#include ++ ++const asn1_static_node CVE_2018_1000654_2_asn1_tab[] = { ++ { "TEST_TREE", 536875024, NULL }, ++ { NULL, 1610612748, NULL }, ++ { "iso", 1073741825, "1"}, ++ { "identified-organization", 1073741825, "3"}, ++ { "dod", 1073741825, "6"}, ++ { "internet", 1073741825, "1"}, ++ { "security", 1073741825, "5"}, ++ { "mechanisms", 1073741825, "5"}, ++ { "pkix", 1073741825, "7"}, ++ { "id-mod", 1073741825, "0"}, ++ { "id-pkix1-implicit-88", 1, "2"}, ++ { "id-oneTest", 1879048204, NULL }, ++ { NULL, 1073741825, "id-two"}, ++ { NULL, 1073741825, "9"}, ++ { NULL, 1, "1"}, ++ { "id-two", 1879048204, NULL }, ++ { NULL, 1073741825, "id-three"}, ++ { NULL, 1073741825, "2"}, ++ { NULL, 1, "2"}, ++ { "id-three", 1879048204, NULL }, ++ { NULL, 1073741825, "id-four"}, ++ { NULL, 1073741825, "3"}, ++ { NULL, 1, "3"}, ++ { "id-four", 805306380, NULL }, ++ { NULL, 1073741825, "id-two"}, ++ { NULL, 1073741825, "3"}, ++ { NULL, 1, "3"}, ++ { NULL, 0, NULL } ++}; +diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c +new file mode 100644 +index 000000000..534e30452 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ */ ++ ++/****************************************************************/ ++/* Description: reproducer for CVE-2018-1000654 */ ++/****************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++#include "CVE-2018-1000654-1_asn1_tab.h" ++#include "CVE-2018-1000654-2_asn1_tab.h" ++ ++void ++test_CVE_2018_1000654 (void) ++{ ++ int result; ++ asn1_node definitions = NULL; ++ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ ++ result = asn1_array2tree (CVE_2018_1000654_1_asn1_tab, &definitions, errorDescription); ++ if (result != ASN1_RECURSION) ++ { ++ grub_fatal ("Error: %s\nErrorDescription = %s\n\n", ++ asn1_strerror (result), errorDescription); ++ return; ++ } ++ ++ asn1_delete_structure (&definitions); ++ ++ result = asn1_array2tree (CVE_2018_1000654_2_asn1_tab, &definitions, errorDescription); ++ if (result != ASN1_RECURSION) ++ { ++ grub_fatal ("Error: %s\nErrorDescription = %s\n\n", ++ asn1_strerror (result), errorDescription); ++ return; ++ } ++ ++ asn1_delete_structure (&definitions); ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c b/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c +new file mode 100644 +index 000000000..f48aea0ef +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c +@@ -0,0 +1,138 @@ ++/* ++ * Copyright (C) 2012-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ */ ++ ++/* Written by Simon Josefsson */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++void ++test_overflow(void) ++{ ++ /* Test that values larger than long are rejected. This has worked ++ fine with all versions of libtasn1. */ ++ ++ { ++ unsigned char der[] = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"; ++ long l; ++ int len; ++ ++ l = asn1_get_length_der (der, sizeof der, &len); ++ ++ if (l != -2L) ++ { ++ grub_fatal ("ERROR: asn1_get_length_der bignum (l %ld len %d)\n", l, len); ++ return; ++ } ++ } ++ ++ /* Test that values larger than int but smaller than long are ++ rejected. This limitation was introduced with libtasn1 2.12. */ ++#if (GRUB_LONG_MAX > GRUB_INT_MAX) ++ { ++ unsigned long num = ((long) GRUB_UINT_MAX) << 2; ++ unsigned char der[20]; ++ int der_len; ++ long l; ++ int len; ++ ++ asn1_length_der (num, der, &der_len); ++ ++ l = asn1_get_length_der (der, der_len, &len); ++ ++ if (l != -2L) ++ { ++ grub_fatal ("ERROR: asn1_get_length_der intnum (l %ld len %d)\n", l, ++ len); ++ return; ++ } ++ } ++#endif ++ ++ /* Test that values larger than would fit in the input string are ++ rejected. This problem was fixed in libtasn1 2.12. */ ++ { ++ unsigned long num = 64; ++ unsigned char der[20]; ++ int der_len; ++ long l; ++ int len; ++ ++ asn1_length_der (num, der, &der_len); ++ ++ der_len = sizeof (der); ++ l = asn1_get_length_der (der, der_len, &len); ++ ++ if (l != -4L) ++ { ++ grub_fatal ("ERROR: asn1_get_length_der overflow-small (l %ld len %d)\n", ++ l, len); ++ return; ++ } ++ } ++ ++ /* Test that values larger than would fit in the input string are ++ rejected. This problem was fixed in libtasn1 2.12. */ ++ { ++ unsigned long num = 1073741824; ++ unsigned char der[20]; ++ int der_len; ++ long l; ++ int len; ++ ++ asn1_length_der (num, der, &der_len); ++ ++ der_len = sizeof (der); ++ l = asn1_get_length_der (der, der_len, &len); ++ ++ if (l != -4L) ++ { ++ grub_fatal ("ERROR: asn1_get_length_der overflow-large1 (l %ld len %d)\n", ++ l, len); ++ return; ++ } ++ } ++ ++ /* Test that values larger than would fit in the input string are ++ rejected. This problem was fixed in libtasn1 2.12. */ ++ { ++ unsigned long num = 2147483649; ++ unsigned char der[20]; ++ int der_len; ++ long l; ++ int len; ++ ++ asn1_length_der (num, der, &der_len); ++ ++ der_len = sizeof (der); ++ l = asn1_get_length_der (der, der_len, &len); ++ ++ if (l != -2L) ++ { ++ grub_fatal ("ERROR: asn1_get_length_der overflow-large2 (l %ld len %d)\n", ++ l, len); ++ return; ++ } ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_simple.c b/grub-core/lib/libtasn1_wrap/tests/Test_simple.c +new file mode 100644 +index 000000000..9f01006dd +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/Test_simple.c +@@ -0,0 +1,207 @@ ++/* ++ * Copyright (C) 2011-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ * Written by Simon Josefsson ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++struct tv ++{ ++ int bitlen; ++ const char *bitstr; ++ int derlen; ++ const char *der; ++}; ++ ++static const struct tv tv[] = { ++ {0, "", 2, "\x01\x00"}, ++ {1, "\x00", 3, "\x02\x07\x00"}, ++ {2, "\x00", 3, "\x02\x06\x00"}, ++ {3, "\x00", 3, "\x02\x05\x00"}, ++ {4, "\x00", 3, "\x02\x04\x00"}, ++ {5, "\x00", 3, "\x02\x03\x00"}, ++ {6, "\x00", 3, "\x02\x02\x00"}, ++ {7, "\x00", 3, "\x02\x01\x00"}, ++ {8, "\x00\x00", 3, "\x02\x00\x00"}, ++ {9, "\x00\x00", 4, "\x03\x07\x00\x00"}, ++ {10, "\x00\x00", 4, "\x03\x06\x00\x00"}, ++ {11, "\x00\x00", 4, "\x03\x05\x00\x00"}, ++ {12, "\x00\x00", 4, "\x03\x04\x00\x00"}, ++ {13, "\x00\x00", 4, "\x03\x03\x00\x00"}, ++ {14, "\x00\x00", 4, "\x03\x02\x00\x00"}, ++ {15, "\x00\x00", 4, "\x03\x01\x00\x00"}, ++ {16, "\x00\x00", 4, "\x03\x00\x00\x00"}, ++ {17, "\x00\x00\x00", 5, "\x04\x07\x00\x00\x00"}, ++ {18, "\x00\x00\x00", 5, "\x04\x06\x00\x00\x00"}, ++ {19, "\x00\x00\x00", 5, "\x04\x05\x00\x00\x00"}, ++ {1, "\xFF", 3, "\x02\x07\x80"}, ++ {2, "\xFF", 3, "\x02\x06\xc0"}, ++ {3, "\xFF", 3, "\x02\x05\xe0"}, ++ {4, "\xFF", 3, "\x02\x04\xf0"}, ++ {5, "\xFF", 3, "\x02\x03\xf8"}, ++ {6, "\xFF", 3, "\x02\x02\xfc"}, ++ {7, "\xFF", 3, "\x02\x01\xfe"}, ++ {8, "\xFF\xFF", 3, "\x02\x00\xff"}, ++ {9, "\xFF\xFF", 4, "\x03\x07\xff\x80"}, ++ {10, "\xFF\xFF", 4, "\x03\x06\xff\xc0"}, ++ {11, "\xFF\xFF", 4, "\x03\x05\xff\xe0"}, ++ {12, "\xFF\xFF", 4, "\x03\x04\xff\xf0"}, ++ {13, "\xFF\xFF", 4, "\x03\x03\xff\xf8"}, ++ {14, "\xFF\xFF", 4, "\x03\x02\xff\xfc"}, ++ {15, "\xFF\xFF", 4, "\x03\x01\xff\xfe"}, ++ {16, "\xFF\xFF", 4, "\x03\x00\xff\xff"}, ++ {17, "\xFF\xFF\xFF", 5, "\x04\x07\xff\xff\x80"}, ++ {18, "\xFF\xFF\xFF", 5, "\x04\x06\xff\xff\xc0"}, ++ {19, "\xFF\xFF\xFF", 5, "\x04\x05\xff\xff\xe0"}, ++}; ++ ++void ++test_simple (void) ++{ ++ int result; ++ unsigned char der[100]; ++ unsigned char str[100]; ++ int der_len = sizeof (der); ++ int str_size = sizeof (str); ++ int ret_len, bit_len; ++ grub_size_t i; ++ ++ /* Dummy test */ ++ ++ asn1_bit_der (NULL, 0, der, &der_len); ++ result = asn1_get_bit_der (der, 0, &ret_len, str, str_size, &bit_len); ++ if (result != ASN1_GENERIC_ERROR) ++ { ++ grub_fatal ("asn1_get_bit_der zero\n"); ++ return; ++ } ++ ++ /* Encode short strings with increasing bit lengths */ ++ ++ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) ++ { ++ /* Encode */ ++ ++ asn1_bit_der ((const unsigned char *) tv[i].bitstr, tv[i].bitlen, ++ der, &der_len); ++ ++#if 0 ++ { ++ size_t j; ++ for (j = 0; j < der_len; j++) ++ printf ("\\x%02x", der[j]); ++ printf ("\n"); ++ } ++#endif ++ ++ if (der_len != tv[i].derlen || grub_memcmp (der, tv[i].der, der_len) != 0) ++ { ++ grub_fatal ("asn1_bit_der iter %lu\n", (unsigned long) i); ++ return; ++ } ++ ++ /* Decode it */ ++ ++ result = asn1_get_bit_der (der, der_len, &ret_len, str, ++ str_size, &bit_len); ++ if (result != ASN1_SUCCESS || ret_len != tv[i].derlen ++ || bit_len != tv[i].bitlen) ++ { ++ grub_fatal ("asn1_get_bit_der iter %lu, err: %d\n", (unsigned long) i, result); ++ return; ++ } ++ } ++ ++ ++ /* Decode sample from "A Layman's Guide to a Subset of ASN.1, BER, ++ and DER" section 5.4 "BIT STRING": "The BER encoding of the BIT ++ STRING value "011011100101110111" can be any of the following, ++ among others, depending on the choice of padding bits, the form ++ of length octets [...]". ++ */ ++ ++ /* 03 04 06 6e 5d c0 DER encoding */ ++ ++ grub_memcpy (der, "\x04\x06\x6e\x5d\xc0", 5); ++ der_len = 5; ++ ++ result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len); ++ if (result != ASN1_SUCCESS || ret_len != 5 ++ || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0) ++ { ++ grub_fatal ("asn1_get_bit_der example\n"); ++ return; ++ } ++ ++ der_len = sizeof (der); ++ asn1_bit_der (str, bit_len, der, &der_len); ++ if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0) ++ { ++ grub_fatal ("asn1_bit_der example roundtrip\n"); ++ return; ++ } ++ ++ /* 03 04 06 6e 5d e0 padded with "100000" */ ++ ++ grub_memcpy (der, "\x04\x06\x6e\x5d\xe0", 5); ++ der_len = 5; ++ ++ result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len); ++ if (result != ASN1_SUCCESS || ret_len != 5 ++ || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xe0", 3) != 0) ++ { ++ grub_fatal ("asn1_get_bit_der example padded\n"); ++ return; ++ } ++ ++ der_len = sizeof (der); ++ asn1_bit_der (str, bit_len, der, &der_len); ++ if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0) ++ { ++ grub_fatal ("asn1_bit_der example roundtrip\n"); ++ return; ++ } ++ ++ /* 03 81 04 06 6e 5d c0 long form of length octets */ ++ ++ grub_memcpy (der, "\x81\x04\x06\x6e\x5d\xc0", 6); ++ der_len = 6; ++ ++ result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len); ++ ++ if (result != ASN1_SUCCESS || ret_len != 6 ++ || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0) ++ { ++ grub_fatal ("asn1_get_bit_der example long form\n"); ++ return; ++ } ++ ++ der_len = sizeof (der); ++ asn1_bit_der (str, bit_len, der, &der_len); ++ if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0) ++ { ++ grub_fatal ("asn1_bit_der example roundtrip\n"); ++ return; ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_strings.c b/grub-core/lib/libtasn1_wrap/tests/Test_strings.c +new file mode 100644 +index 000000000..dbe1474b2 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/Test_strings.c +@@ -0,0 +1,150 @@ ++/* ++ * Copyright (C) 2012-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ * Written by Simon Josefsson ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++struct tv ++{ ++ unsigned int etype; ++ unsigned int str_len; ++ const void *str; ++ unsigned int der_len; ++ const void *der; ++}; ++ ++static const struct tv tv[] = { ++ {ASN1_ETYPE_IA5_STRING, 20, ++ "\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72", ++ 22, ++ "\x16\x14\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72"}, ++ {ASN1_ETYPE_PRINTABLE_STRING, 5, "\x4e\x69\x6b\x6f\x73", ++ 7, "\x13\x05\x4e\x69\x6b\x6f\x73"}, ++ {ASN1_ETYPE_UTF8_STRING, 12, "Αττική", ++ 14, "\x0c\x0c\xce\x91\xcf\x84\xcf\x84\xce\xb9\xce\xba\xce\xae"}, ++ {ASN1_ETYPE_TELETEX_STRING, 15, ++ "\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e", ++ 17, ++ "\x14\x0f\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e"}, ++ {ASN1_ETYPE_OCTET_STRING, 36, ++ "\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A", ++ 38, ++ "\x04\x24\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A"} ++}; ++ ++#define SSTR(x) sizeof(x)-1,x ++static const struct tv ber[] = { ++ {ASN1_ETYPE_OCTET_STRING, ++ SSTR("\xa0\xa0"), ++ SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x00\x00")}, ++ {ASN1_ETYPE_OCTET_STRING, ++ SSTR("\xa0\xa0\xb0\xb0\xb0"), ++ SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x00\x00")}, ++ {ASN1_ETYPE_OCTET_STRING, ++ SSTR("\xa0\xa0\xb0\xb0\xb0\xa1\xa1"), ++ SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x00\x00\x00\x00")}, ++ {ASN1_ETYPE_OCTET_STRING, ++ SSTR("\xa0\xa0\xb0\xb0\xb0\xa1\xa1\xc1"), ++ SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x04\x82\x00\x01\xc1\x00\x00\x00\x00")}, ++}; ++ ++void ++test_strings () ++{ ++ int ret; ++ unsigned char tl[ASN1_MAX_TL_SIZE]; ++ unsigned int tl_len, der_len, str_len; ++ const unsigned char *str; ++ unsigned char *b; ++ unsigned int i; ++ ++ /* Dummy test */ ++ ++ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) ++ { ++ /* Encode */ ++ tl_len = sizeof (tl); ++ ret = asn1_encode_simple_der (tv[i].etype, tv[i].str, tv[i].str_len, ++ tl, &tl_len); ++ if (ret != ASN1_SUCCESS) ++ { ++ grub_fatal ("Encoding error in %u: %s\n", i, ++ asn1_strerror (ret)); ++ return; ++ } ++ der_len = tl_len + tv[i].str_len; ++ ++ if (der_len != tv[i].der_len || grub_memcmp (tl, tv[i].der, tl_len) != 0) ++ { ++ grub_fatal ( ++ "DER encoding differs in %u! (size: %u, expected: %u)\n", ++ i, der_len, tv[i].der_len); ++ return; ++ } ++ ++ /* decoding */ ++ ret = ++ asn1_decode_simple_der (tv[i].etype, tv[i].der, tv[i].der_len, &str, ++ &str_len); ++ if (ret != ASN1_SUCCESS) ++ { ++ grub_fatal ("Decoding error in %u: %s\n", i, ++ asn1_strerror (ret)); ++ return; ++ } ++ ++ if (str_len != tv[i].str_len || grub_memcmp (str, tv[i].str, str_len) != 0) ++ { ++ grub_fatal ( ++ "DER decoded data differ in %u! (size: %u, expected: %u)\n", ++ i, der_len, tv[i].str_len); ++ return; ++ } ++ } ++ ++ /* BER decoding */ ++ for (i = 0; i < sizeof (ber) / sizeof (ber[0]); i++) ++ { ++ /* decoding */ ++ ret = ++ asn1_decode_simple_ber (ber[i].etype, ber[i].der, ber[i].der_len, &b, ++ &str_len, NULL); ++ if (ret != ASN1_SUCCESS) ++ { ++ grub_fatal ("BER decoding error in %u: %s\n", i, ++ asn1_strerror (ret)); ++ return; ++ } ++ ++ if (str_len != ber[i].str_len || grub_memcmp (b, ber[i].str, str_len) != 0) ++ { ++ grub_fatal ( ++ "BER decoded data differ in %u! (size: %u, expected: %u)\n", ++ i, str_len, ber[i].str_len); ++ return; ++ } ++ grub_free(b); ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c b/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c +new file mode 100644 +index 000000000..d367bbfb5 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c +@@ -0,0 +1,116 @@ ++/* ++ * Copyright (C) 2016 Red Hat, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++struct tv ++{ ++ int der_len; ++ const unsigned char *der; ++ const char *oid; ++ int expected_error; ++}; ++ ++static const struct tv tv[] = { ++ {.der_len = 5, ++ .der = (void *) "\x06\x03\x80\x37\x03", ++ .oid = "2.999.3", ++ .expected_error = ASN1_DER_ERROR /* leading 0x80 */ ++ }, ++ {.der_len = 12, ++ .der = (void *) "\x06\x0a\x2b\x06\x01\x80\x01\x92\x08\x09\x05\x01", ++ .oid = "1.3.6.1.4.1.2312.9.5.1", ++ .expected_error = ASN1_DER_ERROR /* leading 0x80 */ ++ }, ++ {.der_len = 6, ++ .der = (void *) "\x06\x04\x01\x02\x03\x04", ++ .oid = "0.1.2.3.4", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 5, ++ .der = (void *) "\x06\x03\x51\x02\x03", ++ .oid = "2.1.2.3", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 5, ++ .der = (void *) "\x06\x03\x88\x37\x03", ++ .oid = "2.999.3", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 12, ++ .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01", ++ .oid = "1.3.6.1.4.1.2312.9.5.1", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 19, ++ .der = (void *) "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d", ++ .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 19, ++ .der = ++ (void *) ++ "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07", ++ .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7", ++ .expected_error = ASN1_SUCCESS}, ++}; ++ ++void ++test_object_id_decoding (void) ++{ ++ char str[128]; ++ int ret, ret_len; ++ grub_size_t i; ++ ++ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) ++ { ++ /* decode */ ++ ret = ++ asn1_get_object_id_der (tv[i].der+1, ++ tv[i].der_len-1, &ret_len, str, ++ sizeof (str)); ++ if (ret != tv[i].expected_error) ++ { ++ grub_fatal ( ++ "%d: asn1_get_object_id_der iter %lu: got '%s' expected %d\n", ++ __LINE__, (unsigned long) i, asn1_strerror(ret), tv[i].expected_error); ++ return; ++ } ++ ++ if (tv[i].expected_error != ASN1_SUCCESS) ++ continue; ++ ++ if (ret_len != tv[i].der_len-1) ++ { ++ grub_fatal ( ++ "%d: iter %lu: error in DER, length returned is %d, had %d\n", ++ __LINE__, (unsigned long)i, ret_len, tv[i].der_len-1); ++ return; ++ } ++ ++ if (grub_strcmp (tv[i].oid, str) != 0) ++ { ++ grub_fatal ( ++ "%d: strcmp iter %lu: got invalid OID: %s, expected: %s\n", ++ __LINE__, (unsigned long) i, str, tv[i].oid); ++ return; ++ } ++ ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c b/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c +new file mode 100644 +index 000000000..3a83b58c5 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c +@@ -0,0 +1,120 @@ ++/* ++ * Copyright (C) 2019 Nikos Mavrogiannopoulos ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++struct tv ++{ ++ int der_len; ++ const unsigned char *der; ++ const char *oid; ++ int expected_error; ++}; ++ ++static const struct tv tv[] = { ++ {.der_len = 0, ++ .der = (void *) "", ++ .oid = "5.999.3", ++ .expected_error = ASN1_VALUE_NOT_VALID /* cannot start with 5 */ ++ }, ++ {.der_len = 0, ++ .der = (void *) "", ++ .oid = "0.48.9", ++ .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 48 */ ++ }, ++ {.der_len = 0, ++ .der = (void *) "", ++ .oid = "1.40.9", ++ .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 40 */ ++ }, ++ {.der_len = 4, ++ .der = (void *) "\x06\x02\x4f\x63", ++ .oid = "1.39.99", ++ .expected_error = ASN1_SUCCESS, ++ }, ++ {.der_len = 6, ++ .der = (void *) "\x06\x04\x01\x02\x03\x04", ++ .oid = "0.1.2.3.4", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 5, ++ .der = (void *) "\x06\x03\x51\x02\x03", ++ .oid = "2.1.2.3", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 5, ++ .der = (void *) "\x06\x03\x88\x37\x03", ++ .oid = "2.999.3", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 12, ++ .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01", ++ .oid = "1.3.6.1.4.1.2312.9.5.1", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 19, ++ .der = (void *) "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d", ++ .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 19, ++ .der = ++ (void *) ++ "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07", ++ .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7", ++ .expected_error = ASN1_SUCCESS}, ++}; ++ ++void ++test_object_id_encoding(void) ++{ ++ unsigned char der[128]; ++ int ret, der_len, i; ++ ++ for (i = 0; i < (int)(sizeof (tv) / sizeof (tv[0])); i++) ++ { ++ der_len = sizeof(der); ++ ret = asn1_object_id_der(tv[i].oid, der, &der_len, 0); ++ if (ret != ASN1_SUCCESS) ++ { ++ if (ret == tv[i].expected_error) ++ continue; ++ grub_fatal ( ++ "%d: iter %lu, encoding of OID failed: %s\n", ++ __LINE__, (unsigned long) i, asn1_strerror(ret)); ++ return; ++ } ++ else if (ret != tv[i].expected_error) ++ { ++ grub_fatal ( ++ "%d: iter %lu, encoding of OID %s succeeded when expecting failure\n", ++ __LINE__, (unsigned long) i, tv[i].oid); ++ return; ++ } ++ ++ if (der_len != tv[i].der_len || grub_memcmp(der, tv[i].der, der_len) != 0) ++ { ++ grub_fatal ( ++ "%d: iter %lu, re-encoding of OID %s resulted to different string (%d vs %d bytes)\n", ++ __LINE__, (unsigned long) i, tv[i].oid, der_len, tv[i].der_len); ++ ++ return; ++ } ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/octet-string.c b/grub-core/lib/libtasn1_wrap/tests/octet-string.c +new file mode 100644 +index 000000000..d8a049e8d +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/octet-string.c +@@ -0,0 +1,211 @@ ++/* ++ * Copyright (C) 2011-2020 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ * Written by Simon Josefsson and Nikos Mavrogiannopoulos ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++ ++struct tv ++{ ++ const char *name; ++ int der_len; ++ const unsigned char *der_str; ++ int len; ++ const unsigned char *string; ++ int expected_error; ++ int ber; ++}; ++ ++static const struct tv tv[] = { ++ {.name = "primitive octet strings", ++ .der_len = 10, ++ .der_str = ++ (void*)"\x04\x08\x01\x23\x45\x67\x89\xab\xcd\xef", ++ .len = 8, ++ .string = ++ (void*)"\x01\x23\x45\x67\x89\xab\xcd\xef", ++ .ber = 0}, ++ {.der_len = 22, ++ .der_str = ++ (void*)"\x04\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27", ++ .len = 20, ++ .string = ++ (void*)"\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27"}, ++ ++ {.name = "long type of length", ++ .der_len = 23, ++ .der_str = ++ (void*)"\x04\x81\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27", ++ .len = 20, ++ .string = ++ (void*)"\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27", ++ .ber = 1}, ++ {.der_len = 11, ++ .der_str = ++ (void*)"\x04\x81\x08\x01\x23\x45\x67\x89\xab\xcd\xef", ++ .len = 8, ++ .string = ++ (void*)"\x01\x23\x45\x67\x89\xab\xcd\xef", ++ .ber = 1}, ++ ++ {.name = "constructed - indefinite", ++ .der_len = 11, ++ .der_str = (void*)"\x24\x80\x04\x05\x01\x02\x03\x04\x05\x00\x00", ++ .len = 5, ++ .string = (void*)"\x01\x02\x03\x04\x05", ++ .ber = 1, ++ }, ++ ++ {.name = "constructed - definite - concat", ++ .der_len = 12, ++ .der_str = (void*)"\x24\x0a\x04\x04\x0a\x0b\x0c\x0d\x04\x02\x0e\x0f", ++ .len = 6, ++ .string = (void*)"\x0a\x0b\x0c\x0d\x0e\x0f", ++ .ber = 1, ++ }, ++ {.name = "constructed - definite - recursive", ++ .der_len = 15, ++ .der_str = (void*)"\x24\x0d\x04\x04\x0a\x0b\x0c\x0d\x24\x05\x04\x00\x04\x01\x0f", ++ .len = 5, ++ .string = (void*)"\x0a\x0b\x0c\x0d\x0f", ++ .ber = 1, ++ }, ++ {.name = "constructed - definite - single", ++ .der_len = 7, ++ .der_str = (void*)"\x24\x05\x04\x03\x01\x02\x03", ++ .len = 3, ++ .string = (void*)"\x01\x02\x03", ++ .ber = 1, ++ }, ++ ++ /* a large amount of recursive indefinite encoding */ ++ {.name = "a large amount of recursive indefinite encoding", ++ .der_len = 29325, ++ .der_str = (void*)"\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80", ++ .len = 0, ++ .ber = 1, ++ .expected_error = ASN1_DER_ERROR ++ } ++}; ++ ++void ++test_octet_string (void) ++{ ++ unsigned char str[100]; ++ unsigned char der[100]; ++ int der_len = sizeof (der); ++ int str_size = sizeof (str); ++ unsigned char *tmp = NULL; ++ int ret, ret_len; ++ grub_size_t i; ++ ++ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) ++ { ++ /* Decode */ ++ ++ if (tv[i].ber == 0) ++ { ++ str_size = sizeof (str); ++ ret = ++ asn1_get_octet_der (tv[i].der_str + 1, ++ tv[i].der_len - 1, &ret_len, str, ++ sizeof (str), &str_size); ++ if (ret != tv[i].expected_error) ++ { ++ grub_fatal ( ++ "%d: asn1_get_octet_der: %s: got %d expected %d\n", ++ __LINE__, tv[i].name, ret, ++ tv[i].expected_error); ++ return; ++ } ++ if (tv[i].expected_error) ++ continue; ++ ++ if (ret_len != tv[i].der_len - 1) ++ { ++ grub_fatal ( ++ "%d: error in DER, length returned is %d, had %d\n", ++ __LINE__, ret_len, tv[i].der_len - 1); ++ return; ++ } ++ ++ if (str_size != tv[i].len ++ || grub_memcmp (tv[i].string, str, tv[i].len) != 0) ++ { ++ grub_fatal ( ++ "%d: memcmp: %s: got invalid decoding\n", ++ __LINE__, tv[i].name); ++ ++ return; ++ } ++ ++ /* Encode */ ++ der_len = sizeof (der); ++ asn1_octet_der (str, str_size, der, &der_len); ++ ++ if (der_len != tv[i].der_len - 1 ++ || grub_memcmp (tv[i].der_str + 1, der, tv[i].der_len - 1) != 0) ++ { ++ grub_fatal ( ++ "encoding: %s: got invalid encoding\n", ++ tv[i].name); ++ return; ++ } ++ } ++ ++ ret = ++ asn1_decode_simple_ber (ASN1_ETYPE_OCTET_STRING, ++ tv[i].der_str, tv[i].der_len, ++ &tmp, (unsigned int*)&str_size, (unsigned int*)&der_len); ++ if (ret != tv[i].expected_error) ++ { ++ grub_fatal ( ++ "%d: asn1_decode_simple_ber: %s: got %s expected %s\n", ++ __LINE__, tv[i].name, asn1_strerror(ret), asn1_strerror(tv[i].expected_error)); ++ return; ++ } ++ if (tv[i].expected_error) ++ continue; ++ ++ if (der_len != tv[i].der_len) ++ { ++ grub_fatal ( ++ "%d: error: %s: DER, length returned is %d, had %d\n", ++ __LINE__, tv[i].name, der_len, tv[i].der_len); ++ return; ++ } ++ ++ if (str_size != tv[i].len || grub_memcmp (tv[i].string, tmp, tv[i].len) != 0) ++ { ++ grub_fatal ( ++ "%d: memcmp: %s: got invalid decoding\n", ++ __LINE__, tv[i].name); ++ return; ++ } ++ grub_free (tmp); ++ tmp = NULL; ++ ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/reproducers.c b/grub-core/lib/libtasn1_wrap/tests/reproducers.c +new file mode 100644 +index 000000000..dc7268d4c +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/reproducers.c +@@ -0,0 +1,81 @@ ++/* ++ * Copyright (C) 2019 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ */ ++ ++/****************************************************************/ ++/* Description: run reproducers for several fixed issues */ ++/****************************************************************/ ++ ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++#define CONST_DOWN (1U<<29) ++ ++/* produces endless loop (fixed by d4b624b2): ++ * The following translates into a single node with all pointers ++ * (right,left,down) set to NULL. */ ++const asn1_static_node endless_asn1_tab[] = { ++ { "TEST_TREE", 536875024, NULL }, ++ { NULL, 0, NULL } ++}; ++ ++/* produces memory leak (fixed by f16d1ff9): ++ * 152 bytes in 1 blocks are definitely lost in loss record 1 of 1 ++ * at 0x4837B65: calloc (vg_replace_malloc.c:762) ++ * by 0x4851C0D: _asn1_add_static_node (parser_aux.c:71) ++ * by 0x4853AAC: asn1_array2tree (structure.c:200) ++ * by 0x10923B: main (single_node.c:67) ++ */ ++const asn1_static_node tab[] = { ++{ "a", CONST_DOWN, "" }, ++{ "b", 0, "" }, ++{ "c", 0, "" }, ++{ NULL, 0, NULL } ++}; ++ ++void ++test_reproducers (void) ++{ ++ int result; ++ asn1_node definitions = NULL; ++ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ ++ result = asn1_array2tree (endless_asn1_tab, &definitions, errorDescription); ++ if (result != ASN1_SUCCESS) ++ { ++ grub_fatal ("Error: %s\nErrorDescription = %s\n\n", ++ asn1_strerror (result), errorDescription); ++ return; ++ } ++ ++ asn1_delete_structure (&definitions); ++ ++ definitions = NULL; ++ result = asn1_array2tree (tab, &definitions, errorDescription); ++ if (result != ASN1_SUCCESS) ++ { ++ grub_fatal ("Error: %s\nErrorDescription = %s\n\n", ++ asn1_strerror (result), errorDescription); ++ return; ++ } ++ ++ asn1_delete_structure (&definitions); ++} +diff --git a/grub-core/lib/libtasn1_wrap/wrap.c b/grub-core/lib/libtasn1_wrap/wrap.c +new file mode 100644 +index 000000000..622ba942e +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/wrap.c +@@ -0,0 +1,26 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++ ++/* ++ * libtasn1 is provided under LGPL2.1+, which is compatible ++ * with GPL3+. As Grub as a whole is under GPL3+, this module ++ * is therefore under GPL3+ also. ++ */ ++GRUB_MOD_LICENSE ("GPLv3+"); +diff --git a/grub-core/lib/libtasn1_wrap/wrap_tests.c b/grub-core/lib/libtasn1_wrap/wrap_tests.c +new file mode 100644 +index 000000000..75fcd21f0 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/wrap_tests.c +@@ -0,0 +1,75 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include "wrap_tests.h" ++ ++/* ++ * libtasn1 tests - from which this is derived - are provided under GPL3+. ++ */ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_command_t cmd; ++ ++static grub_err_t ++grub_cmd_asn1test (grub_command_t cmdd __attribute__((unused)), ++ int argc __attribute__((unused)), ++ char **args __attribute__((unused))) ++{ ++ grub_printf ("test_CVE_2018_1000654\n"); ++ test_CVE_2018_1000654 (); ++ ++ grub_printf ("test_object_id_decoding\n"); ++ test_object_id_decoding (); ++ ++ grub_printf ("test_object_id_encoding\n"); ++ test_object_id_encoding (); ++ ++ grub_printf ("test_octet_string\n"); ++ test_octet_string (); ++ ++ grub_printf ("test_overflow\n"); ++ test_overflow (); ++ ++ grub_printf ("test_reproducers\n"); ++ test_overflow (); ++ ++ grub_printf ("test_simple\n"); ++ test_simple (); ++ ++ grub_printf ("test_strings\n"); ++ test_strings (); ++ ++ grub_printf ("ASN.1 self-tests passed\n"); ++ ++ return GRUB_ERR_NONE; ++} ++ ++ ++GRUB_MOD_INIT(test_asn1) ++{ ++ cmd = grub_register_command ("test_asn1", grub_cmd_asn1test, NULL, ++ "Run self-tests for the ASN.1 parser."); ++} ++ ++GRUB_MOD_FINI(test_asn1) ++{ ++ grub_unregister_command (cmd); ++} +diff --git a/grub-core/lib/libtasn1_wrap/wrap_tests.h b/grub-core/lib/libtasn1_wrap/wrap_tests.h +new file mode 100644 +index 000000000..555e56dd2 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/wrap_tests.h +@@ -0,0 +1,38 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef LIBTASN1_WRAP_TESTS_H ++#define LIBTASN1_WRAP_TESTS_H ++ ++void test_CVE_2018_1000654 (void); ++ ++void test_object_id_encoding (void); ++ ++void test_object_id_decoding (void); ++ ++void test_octet_string (void); ++ ++void test_overflow (void); ++ ++void test_reproducers (void); ++ ++void test_simple (void); ++ ++void test_strings (void); ++ ++#endif +diff --git a/grub-core/lib/pkcs1_v15.c b/grub-core/lib/pkcs1_v15.c +new file mode 100644 +index 000000000..dbacd563d +--- /dev/null ++++ b/grub-core/lib/pkcs1_v15.c +@@ -0,0 +1,59 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2013 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++/* ++ * Given a hash value 'hval', of hash specification 'hash', perform ++ * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod' ++ * (see RFC 8017 s 9.2) and place the result in 'hmpi'. ++ */ ++gcry_err_code_t ++grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval, ++ const gcry_md_spec_t * hash, gcry_mpi_t mod) ++{ ++ grub_size_t tlen, emlen, fflen; ++ grub_uint8_t *em, *emptr; ++ unsigned nbits = gcry_mpi_get_nbits (mod); ++ int ret; ++ tlen = hash->mdlen + hash->asnlen; ++ emlen = (nbits + 7) / 8; ++ if (emlen < tlen + 11) ++ return GPG_ERR_TOO_SHORT; ++ ++ em = grub_malloc (emlen); ++ if (!em) ++ return 1; ++ ++ em[0] = 0x00; ++ em[1] = 0x01; ++ fflen = emlen - tlen - 3; ++ for (emptr = em + 2; emptr < em + 2 + fflen; emptr++) ++ *emptr = 0xff; ++ *emptr++ = 0x00; ++ grub_memcpy (emptr, hash->asnoid, hash->asnlen); ++ emptr += hash->asnlen; ++ grub_memcpy (emptr, hval, hash->mdlen); ++ ++ ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0); ++ grub_free (em); ++ return ret; ++} +diff --git a/grub-core/lib/posix_wrap/limits.h b/grub-core/lib/posix_wrap/limits.h +index 26918c8a0..4be7b4080 100644 +--- a/grub-core/lib/posix_wrap/limits.h ++++ b/grub-core/lib/posix_wrap/limits.h +@@ -41,5 +41,6 @@ + #define LONG_MAX GRUB_LONG_MAX + + #define CHAR_BIT 8 ++#define WORD_BIT 32 + + #endif +diff --git a/grub-core/lib/posix_wrap/stdlib.h b/grub-core/lib/posix_wrap/stdlib.h +index f5279756a..14e4efdd0 100644 +--- a/grub-core/lib/posix_wrap/stdlib.h ++++ b/grub-core/lib/posix_wrap/stdlib.h +@@ -64,4 +64,12 @@ abort (void) + grub_abort (); + } + ++#define strtol grub_strtol ++ ++/* for libgcrypt */ ++#define HAVE_STRTOUL ++#define strtoul grub_strtoul ++ ++#define strtoull grub_strtoull ++ + #endif +diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h +index eeda543c4..2f3e86549 100644 +--- a/grub-core/lib/posix_wrap/sys/types.h ++++ b/grub-core/lib/posix_wrap/sys/types.h +@@ -50,6 +50,7 @@ typedef grub_uint8_t byte; + typedef grub_addr_t uintptr_t; + + #define SIZEOF_UNSIGNED_LONG GRUB_CPU_SIZEOF_LONG ++#define SIZEOF_UNSIGNED_LONG_INT GRUB_CPU_SIZEOF_LONG + #define SIZEOF_UNSIGNED_INT 4 + #define SIZEOF_UNSIGNED_LONG_LONG 8 + #define SIZEOF_UNSIGNED_SHORT 2 +diff --git a/grub-core/lib/progress.c b/grub-core/lib/progress.c +index 4f4389dd5..eb1b7d13c 100644 +--- a/grub-core/lib/progress.c ++++ b/grub-core/lib/progress.c +@@ -72,7 +72,7 @@ grub_file_progress_hook_real (grub_disk_addr_t sector __attribute__ ((unused)), + * 100ULL * 1000ULL, + now - file->last_progress_time, 0); + +- if (file->size == 0) ++ if (file->size <= 0) + percent = 100; + else + percent = grub_divmod64 (100 * file->progress_offset, +diff --git a/grub-core/lib/reed_solomon.c b/grub-core/lib/reed_solomon.c +index 562bd2e3e..5fee7f2a1 100644 +--- a/grub-core/lib/reed_solomon.c ++++ b/grub-core/lib/reed_solomon.c +@@ -162,7 +162,7 @@ static void + rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs) + { + gf_single_t *rs_polynomial; +- int i, j; ++ unsigned int i, j; + gf_single_t *m; + m = xcalloc (s + rs, sizeof (gf_single_t)); + grub_memcpy (m, data, s * sizeof (gf_single_t)); +@@ -333,7 +333,7 @@ static void + encode_block (gf_single_t *ptr, grub_size_t s, + gf_single_t *rptr, grub_size_t rs) + { +- int i, j; ++ unsigned int i, j; + for (i = 0; i < SECTOR_SIZE; i++) + { + grub_size_t ds = (s + SECTOR_SIZE - 1 - i) / SECTOR_SIZE; +diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c +index 26e1472c9..5d7c8603d 100644 +--- a/grub-core/loader/arm64/xen_boot.c ++++ b/grub-core/loader/arm64/xen_boot.c +@@ -252,8 +252,10 @@ xen_boot (void) + return err; + + return grub_arch_efi_linux_boot_image (xen_hypervisor->start, +- xen_hypervisor->size, +- xen_hypervisor->cmdline); ++ xen_hypervisor->size, ++ xen_hypervisor->cmdline, ++ 0); ++ + } + + static void +diff --git a/grub-core/loader/efi/appleloader.c b/grub-core/loader/efi/appleloader.c +index a0b61a240..35d53c5f8 100644 +--- a/grub-core/loader/efi/appleloader.c ++++ b/grub-core/loader/efi/appleloader.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -227,6 +228,9 @@ static grub_command_t cmd; + + GRUB_MOD_INIT(appleloader) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + cmd = grub_register_command ("appleloader", grub_cmd_appleloader, + N_("[OPTS]"), + /* TRANSLATORS: This command is used on EFI to +@@ -238,5 +242,8 @@ GRUB_MOD_INIT(appleloader) + + GRUB_MOD_FINI(appleloader) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + grub_unregister_command (cmd); + } +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 1de98f783..7652f5a92 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -32,6 +33,9 @@ + #include + #include + #include ++#include ++#include ++#include + #include + #include + #include +@@ -45,35 +49,27 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; + +-static grub_err_t +-grub_chainloader_unload (void *context) +-{ +- grub_efi_handle_t image_handle = (grub_efi_handle_t) context; +- grub_efi_loaded_image_t *loaded_image; +- grub_efi_boot_services_t *b; +- +- loaded_image = grub_efi_get_loaded_image (image_handle); +- if (loaded_image != NULL) +- grub_free (loaded_image->load_options); +- +- b = grub_efi_system_table->boot_services; +- b->unload_image (image_handle); +- +- grub_dl_unref (my_mod); +- return GRUB_ERR_NONE; +-} ++struct grub_secureboot_chainloader_context { ++ grub_efi_physical_address_t address; ++ grub_efi_uintn_t pages; ++ grub_ssize_t fsize; ++ grub_efi_device_path_t *file_path; ++ grub_efi_char16_t *cmdline; ++ grub_ssize_t cmdline_len; ++ grub_efi_handle_t dev_handle; ++}; + + static grub_err_t +-grub_chainloader_boot (void *context) ++grub_start_image (grub_efi_handle_t handle) + { +- grub_efi_handle_t image_handle = (grub_efi_handle_t) context; + grub_efi_boot_services_t *b; + grub_efi_status_t status; + grub_efi_uintn_t exit_data_size; + grub_efi_char16_t *exit_data = NULL; + + b = grub_efi_system_table->boot_services; +- status = b->start_image (image_handle, &exit_data_size, &exit_data); ++ ++ status = grub_efi_start_image (handle, &exit_data_size, &exit_data); + if (status != GRUB_EFI_SUCCESS) + { + if (exit_data) +@@ -95,13 +91,42 @@ grub_chainloader_boot (void *context) + } + + if (exit_data) +- b->free_pool (exit_data); +- +- grub_loader_unset (); ++ grub_efi_free_pool (exit_data); + + return grub_errno; + } + ++static grub_err_t ++grub_chainloader_unload (void *context) ++{ ++ grub_efi_handle_t image_handle; ++ grub_efi_loaded_image_t *loaded_image; ++ ++ image_handle = (grub_efi_handle_t) context; ++ ++ loaded_image = grub_efi_get_loaded_image (image_handle); ++ if (loaded_image != NULL) ++ grub_free (loaded_image->load_options); ++ ++ grub_efi_unload_image (image_handle); ++ ++ grub_dl_unref (my_mod); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_chainloader_boot (void *context) ++{ ++ grub_efi_handle_t image_handle; ++ grub_err_t err; ++ ++ image_handle = (grub_efi_handle_t) context; ++ err = grub_start_image (image_handle); ++ ++ grub_loader_unset (); ++ return err; ++} ++ + static grub_err_t + copy_file_path (grub_efi_file_path_device_path_t *fp, + const char *str, grub_efi_uint16_t len) +@@ -185,7 +210,6 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename) + /* Fill the file path for the directory. */ + d = (grub_efi_device_path_t *) ((char *) file_path + + ((char *) d - (char *) dp)); +- grub_efi_print_device_path (d); + if (copy_file_path ((grub_efi_file_path_device_path_t *) d, + dir_start, dir_end - dir_start) != GRUB_ERR_NONE) + { +@@ -209,24 +233,732 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename) + return file_path; + } + ++#define SHIM_LOCK_GUID \ ++ { 0x605dab50, 0xe046, 0x4300, { 0xab,0xb6,0x3d,0xd8,0x10,0xdd,0x8b,0x23 } } ++ ++typedef union ++{ ++ struct grub_pe32_header_32 pe32; ++ struct grub_pe32_header_64 pe32plus; ++} grub_pe_header_t; ++ ++struct pe_coff_loader_image_context ++{ ++ grub_efi_uint64_t image_address; ++ grub_efi_uint64_t image_size; ++ grub_efi_uint64_t entry_point; ++ grub_efi_uintn_t size_of_headers; ++ grub_efi_uint16_t image_type; ++ grub_efi_uint16_t number_of_sections; ++ grub_efi_uint32_t section_alignment; ++ struct grub_pe32_section_table *first_section; ++ struct grub_pe32_data_directory *reloc_dir; ++ struct grub_pe32_data_directory *sec_dir; ++ grub_efi_uint64_t number_of_rva_and_sizes; ++ grub_pe_header_t *pe_hdr; ++}; ++ ++typedef struct pe_coff_loader_image_context pe_coff_loader_image_context_t; ++ ++struct grub_efi_shim_lock ++{ ++ grub_efi_status_t (*verify)(void *buffer, ++ grub_efi_uint32_t size); ++ grub_efi_status_t (*hash)(void *data, ++ grub_efi_int32_t datasize, ++ pe_coff_loader_image_context_t *context, ++ grub_efi_uint8_t *sha256hash, ++ grub_efi_uint8_t *sha1hash); ++ grub_efi_status_t (*context)(void *data, ++ grub_efi_uint32_t size, ++ pe_coff_loader_image_context_t *context); ++}; ++ ++typedef struct grub_efi_shim_lock grub_efi_shim_lock_t; ++ ++static grub_efi_boolean_t ++read_header (void *data, grub_efi_uint32_t size, ++ pe_coff_loader_image_context_t *context) ++{ ++ grub_guid_t guid = SHIM_LOCK_GUID; ++ grub_efi_shim_lock_t *shim_lock; ++ grub_efi_status_t status; ++ ++ shim_lock = grub_efi_locate_protocol (&guid, NULL); ++ if (!shim_lock) ++ { ++ grub_dprintf ("chain", "no shim lock protocol"); ++ return 0; ++ } ++ ++ status = shim_lock->context (data, size, context); ++ ++ if (status == GRUB_EFI_SUCCESS) ++ { ++ grub_dprintf ("chain", "context success\n"); ++ return 1; ++ } ++ ++ switch (status) ++ { ++ case GRUB_EFI_UNSUPPORTED: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "context error unsupported"); ++ break; ++ case GRUB_EFI_INVALID_PARAMETER: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "context error invalid parameter"); ++ break; ++ default: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "context error code"); ++ break; ++ } ++ ++ return -1; ++} ++ ++static void* ++image_address (void *image, grub_efi_uint64_t sz, grub_efi_uint64_t adr) ++{ ++ if (adr > sz) ++ return NULL; ++ ++ return ((grub_uint8_t*)image + adr); ++} ++ ++static int ++image_is_64_bit (grub_pe_header_t *pe_hdr) ++{ ++ /* .Magic is the same offset in all cases */ ++ if (pe_hdr->pe32plus.optional_header.magic == GRUB_PE32_PE64_MAGIC) ++ return 1; ++ return 0; ++} ++ ++static const grub_uint16_t machine_type __attribute__((__unused__)) = ++#if defined(__x86_64__) ++ GRUB_PE32_MACHINE_X86_64; ++#elif defined(__aarch64__) ++ GRUB_PE32_MACHINE_ARM64; ++#elif defined(__arm__) ++ GRUB_PE32_MACHINE_ARMTHUMB_MIXED; ++#elif defined(__i386__) || defined(__i486__) || defined(__i686__) ++ GRUB_PE32_MACHINE_I386; ++#elif defined(__ia64__) ++ GRUB_PE32_MACHINE_IA64; ++#elif defined(__riscv) && (__riscv_xlen == 32) ++ GRUB_PE32_MACHINE_RISCV32; ++#elif defined(__riscv) && (__riscv_xlen == 64) ++ GRUB_PE32_MACHINE_RISCV64; ++#else ++#error this architecture is not supported by grub2 ++#endif ++ ++static grub_efi_status_t ++relocate_coff (pe_coff_loader_image_context_t *context, ++ struct grub_pe32_section_table *section, ++ void *orig, void *data) ++{ ++ struct grub_pe32_data_directory *reloc_base, *reloc_base_end; ++ grub_efi_uint64_t adjust; ++ struct grub_pe32_fixup_block *reloc, *reloc_end; ++ char *fixup, *fixup_base, *fixup_data = NULL; ++ grub_efi_uint16_t *fixup_16; ++ grub_efi_uint32_t *fixup_32; ++ grub_efi_uint64_t *fixup_64; ++ grub_efi_uint64_t size = context->image_size; ++ void *image_end = (char *)orig + size; ++ int n = 0; ++ ++ if (image_is_64_bit (context->pe_hdr)) ++ context->pe_hdr->pe32plus.optional_header.image_base = ++ (grub_uint64_t)(unsigned long)data; ++ else ++ context->pe_hdr->pe32.optional_header.image_base = ++ (grub_uint32_t)(unsigned long)data; ++ ++ /* Alright, so here's how this works: ++ * ++ * context->reloc_dir gives us two things: ++ * - the VA the table of base relocation blocks are (maybe) to be ++ * mapped at (reloc_dir->rva) ++ * - the virtual size (reloc_dir->size) ++ * ++ * The .reloc section (section here) gives us some other things: ++ * - the name! kind of. (section->name) ++ * - the virtual size (section->virtual_size), which should be the same ++ * as RelocDir->Size ++ * - the virtual address (section->virtual_address) ++ * - the file section size (section->raw_data_size), which is ++ * a multiple of optional_header->file_alignment. Only useful for image ++ * validation, not really useful for iteration bounds. ++ * - the file address (section->raw_data_offset) ++ * - a bunch of stuff we don't use that's 0 in our binaries usually ++ * - Flags (section->characteristics) ++ * ++ * and then the thing that's actually at the file address is an array ++ * of struct grub_pe32_fixup_block structs with some values packed behind ++ * them. The block_size field of this structure includes the ++ * structure itself, and adding it to that structure's address will ++ * yield the next entry in the array. ++ */ ++ ++ reloc_base = image_address (orig, size, section->raw_data_offset); ++ reloc_base_end = image_address (orig, size, section->raw_data_offset ++ + section->virtual_size); ++ ++ grub_dprintf ("chain", "relocate_coff(): reloc_base %p reloc_base_end %p\n", ++ reloc_base, reloc_base_end); ++ ++ if (!reloc_base && !reloc_base_end) ++ return GRUB_EFI_SUCCESS; ++ ++ if (!reloc_base || !reloc_base_end) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc table overflows binary"); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ ++ adjust = (grub_uint64_t)(grub_efi_uintn_t)data - context->image_address; ++ if (adjust == 0) ++ return GRUB_EFI_SUCCESS; ++ ++ while (reloc_base < reloc_base_end) ++ { ++ grub_uint16_t *entry; ++ reloc = (struct grub_pe32_fixup_block *)((char*)reloc_base); ++ ++ if ((reloc_base->size == 0) || ++ (reloc_base->size > context->reloc_dir->size)) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ "Reloc %d block size %d is invalid\n", n, ++ reloc_base->size); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ ++ entry = &reloc->entries[0]; ++ reloc_end = (struct grub_pe32_fixup_block *) ++ ((char *)reloc_base + reloc_base->size); ++ ++ if ((void *)reloc_end < orig || (void *)reloc_end > image_end) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc entry %d overflows binary", ++ n); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ ++ fixup_base = image_address(data, size, reloc_base->rva); ++ ++ if (!fixup_base) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc %d Invalid fixupbase", n); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ ++ while ((void *)entry < (void *)reloc_end) ++ { ++ fixup = fixup_base + (*entry & 0xFFF); ++ switch ((*entry) >> 12) ++ { ++ case GRUB_PE32_REL_BASED_ABSOLUTE: ++ break; ++ case GRUB_PE32_REL_BASED_HIGH: ++ fixup_16 = (grub_uint16_t *)fixup; ++ *fixup_16 = (grub_uint16_t) ++ (*fixup_16 + ((grub_uint16_t)((grub_uint32_t)adjust >> 16))); ++ if (fixup_data != NULL) ++ { ++ *(grub_uint16_t *) fixup_data = *fixup_16; ++ fixup_data = fixup_data + sizeof (grub_uint16_t); ++ } ++ break; ++ case GRUB_PE32_REL_BASED_LOW: ++ fixup_16 = (grub_uint16_t *)fixup; ++ *fixup_16 = (grub_uint16_t) (*fixup_16 + (grub_uint16_t)adjust); ++ if (fixup_data != NULL) ++ { ++ *(grub_uint16_t *) fixup_data = *fixup_16; ++ fixup_data = fixup_data + sizeof (grub_uint16_t); ++ } ++ break; ++ case GRUB_PE32_REL_BASED_HIGHLOW: ++ fixup_32 = (grub_uint32_t *)fixup; ++ *fixup_32 = *fixup_32 + (grub_uint32_t)adjust; ++ if (fixup_data != NULL) ++ { ++ fixup_data = (char *)ALIGN_UP ((grub_addr_t)fixup_data, sizeof (grub_uint32_t)); ++ *(grub_uint32_t *) fixup_data = *fixup_32; ++ fixup_data += sizeof (grub_uint32_t); ++ } ++ break; ++ case GRUB_PE32_REL_BASED_DIR64: ++ fixup_64 = (grub_uint64_t *)fixup; ++ *fixup_64 = *fixup_64 + (grub_uint64_t)adjust; ++ if (fixup_data != NULL) ++ { ++ fixup_data = (char *)ALIGN_UP ((grub_addr_t)fixup_data, sizeof (grub_uint64_t)); ++ *(grub_uint64_t *) fixup_data = *fixup_64; ++ fixup_data += sizeof (grub_uint64_t); ++ } ++ break; ++ default: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ "Reloc %d unknown relocation type %d", ++ n, (*entry) >> 12); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ entry += 1; ++ } ++ reloc_base = (struct grub_pe32_data_directory *)reloc_end; ++ n++; ++ } ++ ++ return GRUB_EFI_SUCCESS; ++} ++ ++static grub_efi_device_path_t * ++grub_efi_get_media_file_path (grub_efi_device_path_t *dp) ++{ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ ++ if (type == GRUB_EFI_END_DEVICE_PATH_TYPE) ++ break; ++ else if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE ++ && subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE) ++ return dp; ++ ++ dp = GRUB_EFI_NEXT_DEVICE_PATH (dp); ++ } ++ ++ return NULL; ++} ++ ++static grub_efi_boolean_t ++handle_image (struct grub_secureboot_chainloader_context *load_context) ++{ ++ grub_efi_boot_services_t *b; ++ grub_efi_loaded_image_t *li, li_bak; ++ grub_efi_status_t efi_status; ++ void *data = (void *)(unsigned long)load_context->address; ++ grub_efi_uint32_t datasize = load_context->fsize; ++ void *buffer = NULL; ++ char *buffer_aligned = NULL; ++ grub_efi_uint32_t i; ++ struct grub_pe32_section_table *section; ++ char *base, *end; ++ pe_coff_loader_image_context_t context; ++ grub_uint32_t section_alignment; ++ grub_uint32_t buffer_size; ++ int found_entry_point = 0; ++ int rc; ++ grub_efi_status_t (__grub_efi_api *entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table); ++ ++ b = grub_efi_system_table->boot_services; ++ ++ rc = read_header (data, datasize, &context); ++ if (rc < 0) ++ { ++ grub_dprintf ("chain", "Failed to read header\n"); ++ goto error_exit; ++ } ++ else if (rc == 0) ++ { ++ grub_dprintf ("chain", "Secure Boot is not enabled\n"); ++ return 0; ++ } ++ else ++ { ++ grub_dprintf ("chain", "Header read without error\n"); ++ } ++ ++ /* ++ * The spec says, uselessly, of SectionAlignment: ++ * ===== ++ * The alignment (in bytes) of sections when they are loaded into ++ * memory. It must be greater than or equal to FileAlignment. The ++ * default is the page size for the architecture. ++ * ===== ++ * Which doesn't tell you whose responsibility it is to enforce the ++ * "default", or when. It implies that the value in the field must ++ * be > FileAlignment (also poorly defined), but it appears visual ++ * studio will happily write 512 for FileAlignment (its default) and ++ * 0 for SectionAlignment, intending to imply PAGE_SIZE. ++ * ++ * We only support one page size, so if it's zero, nerf it to 4096. ++ */ ++ section_alignment = context.section_alignment; ++ if (section_alignment == 0) ++ section_alignment = 4096; ++ ++ buffer_size = context.image_size + section_alignment; ++ grub_dprintf ("chain", "image size is %08"PRIxGRUB_UINT64_T", datasize is %08x\n", ++ context.image_size, datasize); ++ ++ efi_status = b->allocate_pool (GRUB_EFI_LOADER_DATA, ++ buffer_size, (void**)&buffer); ++ ++ if (efi_status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto error_exit; ++ } ++ ++ buffer_aligned = (char *)ALIGN_UP ((grub_addr_t)buffer, section_alignment); ++ if (!buffer_aligned) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto error_exit; ++ } ++ ++ grub_memcpy (buffer_aligned, data, context.size_of_headers); ++ ++ entry_point = image_address (buffer_aligned, context.image_size, ++ context.entry_point); ++ ++ grub_dprintf ("chain", "entry_point: %p\n", entry_point); ++ if (!entry_point) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid entry point"); ++ goto error_exit; ++ } ++ ++ char *reloc_base, *reloc_base_end; ++ grub_dprintf ("chain", "reloc_dir: %p reloc_size: 0x%08x\n", ++ (void *)(unsigned long)context.reloc_dir->rva, ++ context.reloc_dir->size); ++ reloc_base = image_address (buffer_aligned, context.image_size, ++ context.reloc_dir->rva); ++ /* RelocBaseEnd here is the address of the last byte of the table */ ++ reloc_base_end = image_address (buffer_aligned, context.image_size, ++ context.reloc_dir->rva ++ + context.reloc_dir->size - 1); ++ grub_dprintf ("chain", "reloc_base: %p reloc_base_end: %p\n", ++ reloc_base, reloc_base_end); ++ ++ struct grub_pe32_section_table *reloc_section = NULL, fake_reloc_section; ++ ++ section = context.first_section; ++ for (i = 0; i < context.number_of_sections; i++, section++) ++ { ++ char name[9]; ++ ++ base = image_address (buffer_aligned, context.image_size, ++ section->virtual_address); ++ end = image_address (buffer_aligned, context.image_size, ++ section->virtual_address + section->virtual_size -1); ++ ++ grub_strncpy(name, section->name, 9); ++ name[8] = '\0'; ++ grub_dprintf ("chain", "Section %d \"%s\" at %p..%p\n", i, ++ name, base, end); ++ ++ if (end < base) ++ { ++ grub_dprintf ("chain", " base is %p but end is %p... bad.\n", ++ base, end); ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ "Image has invalid negative size"); ++ goto error_exit; ++ } ++ ++ if (section->virtual_address <= context.entry_point && ++ (section->virtual_address + section->raw_data_size - 1) ++ > context.entry_point) ++ { ++ found_entry_point++; ++ grub_dprintf ("chain", " section contains entry point\n"); ++ } ++ ++ /* We do want to process .reloc, but it's often marked ++ * discardable, so we don't want to memcpy it. */ ++ if (grub_memcmp (section->name, ".reloc\0\0", 8) == 0) ++ { ++ if (reloc_section) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ "Image has multiple relocation sections"); ++ goto error_exit; ++ } ++ ++ /* If it has nonzero sizes, and our bounds check ++ * made sense, and the VA and size match RelocDir's ++ * versions, then we believe in this section table. */ ++ if (section->raw_data_size && section->virtual_size && ++ base && end && reloc_base == base) ++ { ++ if (reloc_base_end == end) ++ { ++ grub_dprintf ("chain", " section is relocation section\n"); ++ reloc_section = section; ++ } ++ else if (reloc_base_end && reloc_base_end < end) ++ { ++ /* Bogus virtual size in the reloc section -- RelocDir ++ * reported a smaller Base Relocation Directory. Decrease ++ * the section's virtual size so that it equal RelocDir's ++ * idea, but only for the purposes of relocate_coff(). */ ++ grub_dprintf ("chain", ++ " section is (overlong) relocation section\n"); ++ grub_memcpy (&fake_reloc_section, section, sizeof *section); ++ fake_reloc_section.virtual_size -= (end - reloc_base_end); ++ reloc_section = &fake_reloc_section; ++ } ++ } ++ ++ if (!reloc_section) ++ { ++ grub_dprintf ("chain", " section is not reloc section?\n"); ++ grub_dprintf ("chain", " rds: 0x%08x, vs: %08x\n", ++ section->raw_data_size, section->virtual_size); ++ grub_dprintf ("chain", " base: %p end: %p\n", base, end); ++ grub_dprintf ("chain", " reloc_base: %p reloc_base_end: %p\n", ++ reloc_base, reloc_base_end); ++ } ++ } ++ ++ grub_dprintf ("chain", " Section characteristics are %08x\n", ++ section->characteristics); ++ grub_dprintf ("chain", " Section virtual size: %08x\n", ++ section->virtual_size); ++ grub_dprintf ("chain", " Section raw_data size: %08x\n", ++ section->raw_data_size); ++ if (section->characteristics & GRUB_PE32_SCN_MEM_DISCARDABLE) ++ { ++ grub_dprintf ("chain", " Discarding section\n"); ++ continue; ++ } ++ ++ if (!base || !end) ++ { ++ grub_dprintf ("chain", " section is invalid\n"); ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid section size"); ++ goto error_exit; ++ } ++ ++ if (section->characteristics & GRUB_PE32_SCN_CNT_UNINITIALIZED_DATA) ++ { ++ if (section->raw_data_size != 0) ++ grub_dprintf ("chain", " UNINITIALIZED_DATA section has data?\n"); ++ } ++ else if (section->virtual_address < context.size_of_headers || ++ section->raw_data_offset < context.size_of_headers) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ "Section %d is inside image headers", i); ++ goto error_exit; ++ } ++ ++ if (section->raw_data_size > 0) ++ { ++ grub_dprintf ("chain", " copying 0x%08x bytes to %p\n", ++ section->raw_data_size, base); ++ grub_memcpy (base, ++ (grub_efi_uint8_t*)data + section->raw_data_offset, ++ section->raw_data_size); ++ } ++ ++ if (section->raw_data_size < section->virtual_size) ++ { ++ grub_dprintf ("chain", " padding with 0x%08x bytes at %p\n", ++ section->virtual_size - section->raw_data_size, ++ base + section->raw_data_size); ++ grub_memset (base + section->raw_data_size, 0, ++ section->virtual_size - section->raw_data_size); ++ } ++ ++ grub_dprintf ("chain", " finished section %s\n", name); ++ } ++ ++ /* 5 == EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC */ ++ if (context.number_of_rva_and_sizes <= 5) ++ { ++ grub_dprintf ("chain", "image has no relocation entry\n"); ++ goto error_exit; ++ } ++ ++ if (context.reloc_dir->size && reloc_section) ++ { ++ /* run the relocation fixups */ ++ efi_status = relocate_coff (&context, reloc_section, data, ++ buffer_aligned); ++ ++ if (efi_status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "relocation failed"); ++ goto error_exit; ++ } ++ } ++ ++ if (!found_entry_point) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "entry point is not within sections"); ++ goto error_exit; ++ } ++ if (found_entry_point > 1) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "%d sections contain entry point", ++ found_entry_point); ++ goto error_exit; ++ } ++ ++ li = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (!li) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no loaded image available"); ++ goto error_exit; ++ } ++ ++ grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t)); ++ li->image_base = buffer_aligned; ++ li->image_size = context.image_size; ++ li->load_options = load_context->cmdline; ++ li->load_options_size = load_context->cmdline_len; ++ li->file_path = grub_efi_get_media_file_path (load_context->file_path); ++ li->device_handle = load_context->dev_handle; ++ if (!li->file_path) ++ { ++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file path found"); ++ goto error_exit; ++ } ++ ++ grub_dprintf ("chain", "booting via entry point\n"); ++ efi_status = entry_point (grub_efi_image_handle, ++ grub_efi_system_table); ++ ++ grub_dprintf ("chain", "entry_point returned %ld\n", efi_status); ++ grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t)); ++ efi_status = b->free_pool (buffer); ++ ++ return 1; ++ ++error_exit: ++ grub_dprintf ("chain", "error_exit: grub_errno: %d\n", grub_errno); ++ if (buffer) ++ b->free_pool (buffer); ++ ++ return 0; ++} ++ ++static grub_err_t ++grub_secureboot_chainloader_unload (void *context) ++{ ++ struct grub_secureboot_chainloader_context *sb_context; ++ ++ sb_context = (struct grub_secureboot_chainloader_context *) context; ++ ++ grub_efi_free_pages (sb_context->address, sb_context->pages); ++ grub_free (sb_context->file_path); ++ grub_free (sb_context->cmdline); ++ grub_free (sb_context); ++ ++ grub_dl_unref (my_mod); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_load_image(grub_efi_device_path_t *file_path, void *boot_image, ++ grub_efi_uintn_t image_size, grub_efi_handle_t dev_handle, ++ grub_efi_char16_t *cmdline, grub_ssize_t cmdline_len, ++ grub_efi_handle_t *image_handle_out) ++{ ++ grub_efi_boot_services_t *b; ++ grub_efi_status_t status; ++ grub_efi_loaded_image_t *loaded_image; ++ ++ b = grub_efi_system_table->boot_services; ++ ++ status = grub_efi_load_image (0, grub_efi_image_handle, file_path, ++ boot_image, image_size, image_handle_out); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ if (status == GRUB_EFI_OUT_OF_RESOURCES) ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources"); ++ else ++ grub_error (GRUB_ERR_BAD_OS, "cannot load image"); ++ return -1; ++ } ++ ++ /* LoadImage does not set a device handler when the image is ++ loaded from memory, so it is necessary to set it explicitly here. ++ This is a mess. */ ++ loaded_image = grub_efi_get_loaded_image (*image_handle_out); ++ if (! loaded_image) ++ { ++ grub_error (GRUB_ERR_BAD_OS, "no loaded image available"); ++ return -1; ++ } ++ loaded_image->device_handle = dev_handle; ++ ++ if (cmdline) ++ { ++ loaded_image->load_options = cmdline; ++ loaded_image->load_options_size = cmdline_len; ++ } ++ ++ return 0; ++} ++ ++static grub_err_t ++grub_secureboot_chainloader_boot (void *context) ++{ ++ struct grub_secureboot_chainloader_context *sb_context; ++ grub_efi_boot_services_t *b; ++ int rc; ++ grub_efi_handle_t handle = 0; ++ ++ sb_context = (struct grub_secureboot_chainloader_context *) context; ++ ++ rc = handle_image (sb_context); ++ if (rc == 0) ++ { ++ /* We weren't able to attempt to execute the image, so fall back ++ * to LoadImage / StartImage. ++ */ ++ rc = grub_load_image(sb_context->file_path, ++ (void *)(unsigned long)sb_context->address, ++ sb_context->fsize, sb_context->dev_handle, ++ sb_context->cmdline, sb_context->cmdline_len, ++ &handle); ++ if (rc == 0) ++ grub_start_image (handle); ++ } ++ ++ b = grub_efi_system_table->boot_services; ++ b->unload_image (handle); ++ ++ grub_loader_unset (); ++ return grub_errno; ++} ++ + static grub_err_t + grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { + grub_file_t file = 0; +- grub_ssize_t size; + grub_efi_status_t status; + grub_efi_boot_services_t *b; + grub_device_t dev = 0; +- grub_efi_device_path_t *dp = NULL, *file_path = NULL; +- grub_efi_loaded_image_t *loaded_image; ++ grub_device_t orig_dev = 0; ++ grub_efi_device_path_t *dp = 0, *file_path = 0; + char *filename; + void *boot_image = 0; +- grub_efi_handle_t dev_handle = 0; + grub_efi_physical_address_t address = 0; ++ grub_ssize_t fsize; + grub_efi_uintn_t pages = 0; +- grub_efi_char16_t *cmdline = NULL; +- grub_efi_handle_t image_handle = NULL; ++ grub_efi_char16_t *cmdline = 0; ++ grub_ssize_t cmdline_len = 0; ++ grub_efi_handle_t dev_handle = 0; ++ grub_efi_handle_t image_handle = 0; ++ struct grub_secureboot_chainloader_context *sb_context = 0; ++ ++ file_path = NULL; ++ address = 0; ++ pages = 0; ++ cmdline = NULL; ++ image_handle = NULL; ++ dev_handle = 0; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -236,12 +968,52 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + b = grub_efi_system_table->boot_services; + ++ if (argc > 1) ++ { ++ int i; ++ grub_efi_char16_t *p16; ++ ++ for (i = 1, cmdline_len = 0; i < argc; i++) ++ cmdline_len += grub_strlen (argv[i]) + 1; ++ ++ cmdline_len *= sizeof (grub_efi_char16_t); ++ cmdline = p16 = grub_malloc (cmdline_len); ++ if (! cmdline) ++ goto fail; ++ ++ for (i = 1; i < argc; i++) ++ { ++ char *p8; ++ ++ p8 = argv[i]; ++ while (*p8) ++ *(p16++) = *(p8++); ++ ++ *(p16++) = ' '; ++ } ++ *(--p16) = 0; ++ } ++ ++ + file = grub_file_open (filename, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE); + if (! file) + goto fail; + +- /* Get the root device's device path. */ +- dev = grub_device_open (0); ++ /* Get the device path from filename. */ ++ char *devname = grub_file_get_device_name (filename); ++ dev = grub_device_open (devname); ++ if (devname) ++ grub_free (devname); ++ ++ /* if device is loopback, use underlying dev */ ++ if (dev && dev->disk->dev->id == GRUB_DISK_DEVICE_LOOPBACK_ID) ++ { ++ struct grub_loopback *d; ++ orig_dev = dev; ++ d = dev->disk->data; ++ dev = d->file->device; ++ } ++ + if (dev == NULL) + ; + else if (dev->disk) +@@ -272,19 +1044,16 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + file_path = make_file_path (dp, filename); + if (file_path == NULL) + goto fail; +- +- grub_printf ("file path: "); +- grub_efi_print_device_path (file_path); + } + +- size = grub_file_size (file); +- if (!size) ++ fsize = grub_file_size (file); ++ if (!fsize) + { + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + filename); + goto fail; + } +- pages = (grub_efi_uintn_t) GRUB_EFI_BYTES_TO_PAGES (size); ++ pages = (grub_efi_uintn_t) GRUB_EFI_BYTES_TO_PAGES (fsize); + + status = b->allocate_pages (GRUB_EFI_ALLOCATE_ANY_PAGES, + GRUB_EFI_LOADER_CODE, +@@ -298,7 +1067,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + } + + boot_image = (void *) ((grub_addr_t) address); +- if (grub_file_read (file, boot_image, size) != size) ++ if (grub_file_read (file, boot_image, fsize) != fsize) + { + if (grub_errno == GRUB_ERR_NONE) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +@@ -307,8 +1076,19 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++ /* ++ * The OS kernel is going to set its own permissions when it takes over ++ * paging a few million instructions from now, and load_image() will set up ++ * anything that's needed based on the section headers, so there's no point ++ * in doing anything but clearing the protection bits here. ++ */ ++ grub_dprintf("nx", "setting attributes for %p (%lu bytes) to %llx\n", ++ (void *)(grub_addr_t)address, fsize, 0llu); ++ grub_update_mem_attrs (address, fsize, ++ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X, 0); ++ + #if defined (__i386__) || defined (__x86_64__) +- if (size >= (grub_ssize_t) sizeof (struct grub_macho_fat_header)) ++ if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header)) + { + struct grub_macho_fat_header *head = boot_image; + if (head->magic +@@ -317,6 +1097,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_uint32_t i; + struct grub_macho_fat_arch *archs + = (struct grub_macho_fat_arch *) (head + 1); ++ ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ { ++ grub_error (GRUB_ERR_BAD_OS, ++ "MACHO binaries are forbidden with Secure Boot"); ++ goto fail; ++ } ++ + for (i = 0; i < grub_cpu_to_le32 (head->nfat_arch); i++) + { + if (GRUB_MACHO_CPUTYPE_IS_HOST_CURRENT (archs[i].cputype)) +@@ -331,83 +1119,67 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + > ~grub_cpu_to_le32 (archs[i].size) + || grub_cpu_to_le32 (archs[i].offset) + + grub_cpu_to_le32 (archs[i].size) +- > (grub_size_t) size) ++ > (grub_size_t) fsize) + { + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + filename); + goto fail; + } + boot_image = (char *) boot_image + grub_cpu_to_le32 (archs[i].offset); +- size = grub_cpu_to_le32 (archs[i].size); ++ fsize = grub_cpu_to_le32 (archs[i].size); + } + } + #endif + +- status = b->load_image (0, grub_efi_image_handle, file_path, +- boot_image, size, +- &image_handle); +- if (status != GRUB_EFI_SUCCESS) ++ if (orig_dev) + { +- if (status == GRUB_EFI_OUT_OF_RESOURCES) +- grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources"); +- else +- grub_error (GRUB_ERR_BAD_OS, "cannot load image"); +- +- goto fail; ++ dev = orig_dev; ++ orig_dev = 0; + } + +- /* LoadImage does not set a device handler when the image is +- loaded from memory, so it is necessary to set it explicitly here. +- This is a mess. */ +- loaded_image = grub_efi_get_loaded_image (image_handle); +- if (! loaded_image) ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) + { +- grub_error (GRUB_ERR_BAD_OS, "no loaded image available"); +- goto fail; ++ sb_context = grub_malloc (sizeof (*sb_context)); ++ if (sb_context == NULL) ++ goto fail; ++ sb_context->address = address; ++ sb_context->fsize = fsize; ++ sb_context->pages = pages; ++ sb_context->file_path = file_path; ++ sb_context->cmdline = cmdline; ++ sb_context->cmdline_len = cmdline_len; ++ sb_context->dev_handle = dev_handle; ++ ++ grub_file_close (file); ++ grub_device_close (dev); ++ ++ grub_loader_set_ex (grub_secureboot_chainloader_boot, ++ grub_secureboot_chainloader_unload, sb_context, 0); ++ return 0; + } +- loaded_image->device_handle = dev_handle; +- +- /* Build load options with arguments from chainloader command line. */ +- if (argc > 1) ++ else + { +- int i, len; +- grub_efi_char16_t *p16; +- +- for (i = 1, len = 0; i < argc; i++) +- len += grub_strlen (argv[i]) + 1; +- +- len *= sizeof (grub_efi_char16_t); +- cmdline = p16 = grub_malloc (len); +- if (! cmdline) +- goto fail; ++ grub_load_image(file_path, boot_image, fsize, dev_handle, cmdline, ++ cmdline_len, &image_handle); ++ grub_file_close (file); ++ grub_device_close (dev); + +- for (i = 1; i < argc; i++) +- { +- char *p8; +- +- p8 = argv[i]; +- while (*p8) +- *(p16++) = *(p8++); ++ /* We're finished with the source image buffer and file path now */ ++ b->free_pages (address, pages); ++ grub_free (file_path); + +- *(p16++) = ' '; +- } +- *(--p16) = 0; ++ grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0); + +- loaded_image->load_options = cmdline; +- loaded_image->load_options_size = len; ++ return 0; + } + +- grub_file_close (file); +- grub_device_close (dev); +- +- /* We're finished with the source image buffer and file path now. */ +- b->free_pages (address, pages); +- grub_free (file_path); +- +- grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0); +- return 0; ++fail: + +- fail: ++ if (orig_dev) ++ { ++ dev = orig_dev; ++ orig_dev = 0; ++ } + + if (dev) + grub_device_close (dev); +@@ -419,10 +1191,13 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_free (file_path); + + if (address) +- b->free_pages (address, pages); ++ grub_efi_free_pages (address, pages); ++ ++ if (cmdline) ++ grub_free (cmdline); + + if (image_handle != NULL) +- b->unload_image (image_handle); ++ grub_efi_unload_image (image_handle); + + grub_dl_unref (my_mod); + +diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c +index 439964b9c..e08d8738a 100644 +--- a/grub-core/loader/efi/fdt.c ++++ b/grub-core/loader/efi/fdt.c +@@ -27,6 +27,8 @@ + #include + #include + ++GRUB_MOD_LICENSE ("GPLv3+"); ++ + static void *loaded_fdt; + static void *fdt; + +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index bfbd95aee..5889e3f36 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -25,10 +25,14 @@ + #include + #include + #include ++#include + #include ++#include + #include + #include ++#include + #include ++#include + #include + #include + #include +@@ -39,8 +43,11 @@ GRUB_MOD_LICENSE ("GPLv3+"); + static grub_dl_t my_mod; + static int loaded; + ++static void *kernel_alloc_addr; ++static grub_uint32_t kernel_alloc_pages; + static void *kernel_addr; + static grub_uint64_t kernel_size; ++static grub_uint32_t handover_offset; + + static char *linux_args; + static grub_uint32_t cmdline_size; +@@ -87,6 +94,201 @@ static grub_efi_load_file2_t initrd_lf2 = { + grub_efi_initrd_load_file2 + }; + ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-align" ++#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" ++ ++grub_err_t ++grub_efi_check_nx_image_support (grub_addr_t k_add, ++ grub_size_t k_size, ++ int *nx_supported) ++{ ++ struct grub_dos_header *doshdr; ++ grub_size_t sz = sizeof (*doshdr); ++ ++ struct grub_pe32_header_32 *pe32; ++ struct grub_pe32_header_64 *pe64; ++ ++ int image_is_compatible = 0; ++ int is_64_bit; ++ ++ if (k_size < sz) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small")); ++ ++ doshdr = (void *)k_add; ++ ++ if ((doshdr->magic & 0xffff) != GRUB_DOS_MAGIC) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel DOS magic is invalid")); ++ ++ sz = doshdr->lfanew + sizeof (*pe32); ++ if (k_size < sz) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small")); ++ ++ pe32 = (struct grub_pe32_header_32 *)(k_add + doshdr->lfanew); ++ pe64 = (struct grub_pe32_header_64 *)pe32; ++ ++ if (grub_memcmp (pe32->signature, GRUB_PE32_SIGNATURE, ++ GRUB_PE32_SIGNATURE_SIZE) != 0) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel PE magic is invalid")); ++ ++ switch (pe32->coff_header.machine) ++ { ++ case GRUB_PE32_MACHINE_ARMTHUMB_MIXED: ++ case GRUB_PE32_MACHINE_I386: ++ case GRUB_PE32_MACHINE_RISCV32: ++ is_64_bit = 0; ++ break; ++ case GRUB_PE32_MACHINE_ARM64: ++ case GRUB_PE32_MACHINE_IA64: ++ case GRUB_PE32_MACHINE_RISCV64: ++ case GRUB_PE32_MACHINE_X86_64: ++ is_64_bit = 1; ++ break; ++ default: ++ return grub_error (GRUB_ERR_BAD_OS, N_("PE machine type 0x%04hx unknown"), ++ pe32->coff_header.machine); ++ } ++ ++ if (is_64_bit) ++ { ++ sz = doshdr->lfanew + sizeof (*pe64); ++ if (k_size < sz) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small")); ++ ++ if (pe64->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT) ++ image_is_compatible = 1; ++ } ++ else ++ { ++ if (pe32->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT) ++ image_is_compatible = 1; ++ } ++ ++ *nx_supported = image_is_compatible; ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_efi_check_nx_required (int *nx_required) ++{ ++ grub_efi_status_t status; ++ grub_guid_t guid = GRUB_EFI_SHIM_LOCK_GUID; ++ grub_size_t mok_policy_sz = 0; ++ char *mok_policy = NULL; ++ grub_uint32_t mok_policy_attrs = 0; ++ ++ status = grub_efi_get_variable_with_attributes ("MokPolicy", &guid, ++ &mok_policy_sz, ++ (void **)&mok_policy, ++ &mok_policy_attrs); ++ if (status == GRUB_EFI_NOT_FOUND || ++ mok_policy_sz == 0 || ++ mok_policy == NULL) ++ { ++ *nx_required = 0; ++ return GRUB_ERR_NONE; ++ } ++ ++ *nx_required = 0; ++ if (mok_policy_sz < 1 || ++ mok_policy_attrs != (GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | ++ GRUB_EFI_VARIABLE_RUNTIME_ACCESS) || ++ (mok_policy[mok_policy_sz-1] & GRUB_MOK_POLICY_NX_REQUIRED)) ++ *nx_required = 1; ++ ++ return GRUB_ERR_NONE; ++} ++ ++typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); ++ ++grub_err_t ++grub_efi_linux_boot (grub_addr_t k_address, grub_size_t k_size, ++ grub_off_t h_offset, void *k_params, ++ int nx_supported) ++{ ++ grub_efi_loaded_image_t *loaded_image = NULL; ++ handover_func hf; ++ int offset = 0; ++ grub_uint64_t stack_set_attrs = GRUB_MEM_ATTR_R | ++ GRUB_MEM_ATTR_W | ++ GRUB_MEM_ATTR_X; ++ grub_uint64_t stack_clear_attrs = 0; ++ grub_uint64_t kernel_set_attrs = stack_set_attrs; ++ grub_uint64_t kernel_clear_attrs = stack_clear_attrs; ++ grub_uint64_t attrs; ++ int nx_required = 0; ++ ++#ifdef __x86_64__ ++ offset = 512; ++#endif ++ ++ /* ++ * Since the EFI loader is not calling the LoadImage() and StartImage() ++ * services for loading the kernel and booting respectively, it has to ++ * set the Loaded Image base address. ++ */ ++ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (loaded_image) ++ loaded_image->image_base = (void *)k_address; ++ else ++ grub_dprintf ("linux", "Loaded Image base address could not be set\n"); ++ ++ grub_dprintf ("linux", "kernel_address: %p handover_offset: %p params: %p\n", ++ (void *)k_address, (void *)h_offset, k_params); ++ ++ grub_efi_check_nx_required(&nx_required); ++ ++ if (nx_required && !nx_supported) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel does not support NX loading required by policy")); ++ ++ if (nx_supported) ++ { ++ kernel_set_attrs &= ~GRUB_MEM_ATTR_W; ++ kernel_clear_attrs |= GRUB_MEM_ATTR_W; ++ stack_set_attrs &= ~GRUB_MEM_ATTR_X; ++ stack_clear_attrs |= GRUB_MEM_ATTR_X; ++ } ++ ++ grub_dprintf ("nx", "Setting attributes for 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to r%cx\n", ++ k_address, k_address + k_size - 1, ++ (kernel_set_attrs & GRUB_MEM_ATTR_W) ? 'w' : '-'); ++ grub_update_mem_attrs (k_address, k_size, ++ kernel_set_attrs, kernel_clear_attrs); ++ ++ grub_get_mem_attrs (k_address, 4096, &attrs); ++ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", ++ (grub_addr_t)k_address, ++ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", ++ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", ++ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); ++ if (grub_stack_addr != (grub_addr_t)-1ll) ++ { ++ grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n", ++ grub_stack_addr, grub_stack_addr + grub_stack_size - 1, ++ (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-'); ++ grub_update_mem_attrs (grub_stack_addr, grub_stack_size, ++ stack_set_attrs, stack_clear_attrs); ++ ++ grub_get_mem_attrs (grub_stack_addr, 4096, &attrs); ++ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", ++ grub_stack_addr, ++ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", ++ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", ++ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); ++ } ++ ++#if defined(__i386__) || defined(__x86_64__) ++ asm volatile ("cli"); ++#endif ++ ++ hf = (handover_func)((char *)k_address + h_offset + offset); ++ hf (grub_efi_image_handle, grub_efi_system_table, k_params); ++ ++ return GRUB_ERR_BUG; ++} ++ ++#pragma GCC diagnostic pop ++ + grub_err_t + grub_arch_efi_linux_load_image_header (grub_file_t file, + struct linux_arch_kernel_header * lh) +@@ -95,7 +297,7 @@ grub_arch_efi_linux_load_image_header (grub_file_t file, + if (grub_file_read (file, lh, sizeof (*lh)) < (grub_ssize_t) sizeof (*lh)) + return grub_error(GRUB_ERR_FILE_READ_ERROR, "failed to read Linux image header"); + +- if ((lh->code0 & 0xffff) != GRUB_PE32_MAGIC) ++ if ((lh->code0 & 0xffff) != GRUB_DOS_MAGIC) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled")); + +@@ -139,8 +341,9 @@ grub_arch_efi_linux_load_image_header (grub_file_t file, + static grub_err_t + finalize_params_linux (void) + { +- int node, retval; +- ++ grub_efi_loaded_image_t *loaded_image = NULL; ++ int node, retval, len; ++ grub_err_t err = GRUB_ERR_NONE; + void *fdt; + + /* Set initrd info */ +@@ -149,14 +352,21 @@ finalize_params_linux (void) + fdt = grub_fdt_load (GRUB_EFI_LINUX_FDT_EXTRA_SPACE); + + if (!fdt) +- goto failure; ++ { ++ err = grub_error(GRUB_ERR_BAD_OS, "failed to load FDT"); ++ goto failure; ++ } ++ + + node = grub_fdt_find_subnode (fdt, 0, "chosen"); + if (node < 0) + node = grub_fdt_add_subnode (fdt, 0, "chosen"); + + if (node < 1) +- goto failure; ++ { ++ err = grub_error(grub_errno, "failed to load chosen fdt node."); ++ goto failure; ++ } + + grub_dprintf ("linux", "Initrd @ %p-%p\n", + (void *) initrd_start, (void *) initrd_end); +@@ -164,89 +374,91 @@ finalize_params_linux (void) + retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start", + initrd_start); + if (retval) +- goto failure; ++ { ++ err = grub_error(retval, "Failed to set linux,initrd-start property"); ++ goto failure; ++ } ++ + retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-end", + initrd_end); + if (retval) +- goto failure; ++ { ++ err = grub_error(retval, "Failed to set linux,initrd-end property"); ++ goto failure; ++ } + } + +- if (grub_fdt_install() != GRUB_ERR_NONE) +- goto failure; +- +- return GRUB_ERR_NONE; +- +-failure: +- grub_fdt_unload(); +- return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); +-} +-#endif +- +-grub_err_t +-grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args) +-{ +- grub_efi_memory_mapped_device_path_t *mempath; +- grub_efi_handle_t image_handle; +- grub_efi_boot_services_t *b; +- grub_efi_status_t status; +- grub_efi_loaded_image_t *loaded_image; +- int len; +- +- mempath = grub_malloc (2 * sizeof (grub_efi_memory_mapped_device_path_t)); +- if (!mempath) +- return grub_errno; +- +- mempath[0].header.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE; +- mempath[0].header.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE; +- mempath[0].header.length = grub_cpu_to_le16_compile_time (sizeof (*mempath)); +- mempath[0].memory_type = GRUB_EFI_LOADER_DATA; +- mempath[0].start_address = addr; +- mempath[0].end_address = addr + size; +- +- mempath[1].header.type = GRUB_EFI_END_DEVICE_PATH_TYPE; +- mempath[1].header.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; +- mempath[1].header.length = sizeof (grub_efi_device_path_t); ++ retval = grub_fdt_install(); ++ if (retval != GRUB_ERR_NONE) ++ { ++ err = grub_error(retval, "Failed to install fdt"); ++ goto failure; ++ } + +- b = grub_efi_system_table->boot_services; +- status = b->load_image (0, grub_efi_image_handle, +- (grub_efi_device_path_t *) mempath, +- (void *) addr, size, &image_handle); +- if (status != GRUB_EFI_SUCCESS) +- return grub_error (GRUB_ERR_BAD_OS, "cannot load image"); +- +- grub_dprintf ("linux", "linux command line: '%s'\n", args); ++ grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n", ++ fdt); + + /* Convert command line to UCS-2 */ +- loaded_image = grub_efi_get_loaded_image (image_handle); ++ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); + if (loaded_image == NULL) + { +- grub_error (GRUB_ERR_BAD_FIRMWARE, "missing loaded_image proto"); +- goto unload; ++ err = grub_error(grub_errno, "Failed to install fdt"); ++ goto failure; + } + loaded_image->load_options_size = len = +- (grub_strlen (args) + 1) * sizeof (grub_efi_char16_t); ++ (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t); + loaded_image->load_options = + grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); + if (!loaded_image->load_options) +- return grub_errno; ++ { ++ err = grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters"); ++ goto failure; ++ } + + loaded_image->load_options_size = + 2 * grub_utf8_to_utf16 (loaded_image->load_options, len, +- (grub_uint8_t *) args, len, NULL); ++ (grub_uint8_t *) linux_args, len, NULL); + +- grub_dprintf ("linux", "starting image %p\n", image_handle); +- status = b->start_image (image_handle, 0, NULL); ++ return GRUB_ERR_NONE; ++ ++failure: ++ grub_fdt_unload(); ++ return err; ++} ++#endif + +- /* When successful, not reached */ +- grub_error (GRUB_ERR_BAD_OS, "start_image() returned 0x%" PRIxGRUB_EFI_UINTN_T, status); +- grub_efi_free_pages ((grub_addr_t) loaded_image->load_options, +- GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); +-unload: +- b->unload_image (image_handle); ++static void ++free_params (void) ++{ ++ grub_efi_loaded_image_t *loaded_image = NULL; + +- return grub_errno; ++ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (loaded_image) ++ { ++ if (loaded_image->load_options) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_efi_uintn_t)loaded_image->load_options, ++ GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); ++ loaded_image->load_options = NULL; ++ loaded_image->load_options_size = 0; ++ } + } + ++grub_err_t ++grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args, ++ int nx_supported) ++{ ++ grub_err_t retval; ++ ++ grub_dprintf ("linux", "linux command line: '%s'\n", args); ++ ++ retval = grub_efi_linux_boot (addr, size, handover_offset, ++ (void *)addr, nx_supported); ++ ++ /* Never reached... */ ++ free_params(); ++ return retval; ++ } ++ + static grub_err_t + grub_linux_boot (void) + { +@@ -255,8 +467,10 @@ grub_linux_boot (void) + return grub_errno; + #endif + +- return grub_arch_efi_linux_boot_image ((grub_addr_t) kernel_addr, +- kernel_size, linux_args); ++ return grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr, ++ (grub_size_t)kernel_size, ++ linux_args, ++ 0); + } + + static grub_err_t +@@ -271,9 +485,8 @@ grub_linux_unload (void) + GRUB_EFI_BYTES_TO_PAGES (initrd_end - initrd_start)); + initrd_start = initrd_end = 0; + grub_free (linux_args); +- if (kernel_addr) +- grub_efi_free_pages ((grub_addr_t) kernel_addr, +- GRUB_EFI_BYTES_TO_PAGES (kernel_size)); ++ if (kernel_alloc_addr) ++ grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages); + #if !defined(__i386__) && !defined(__x86_64__) + grub_fdt_unload (); + #endif +@@ -317,16 +530,28 @@ grub_linux_unload (void) + static void * + allocate_initrd_mem (int initrd_pages) + { +- grub_addr_t max_addr; ++ grub_addr_t max_addr = 0; ++ grub_err_t err; ++ void *ret; + +- if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE) +- return NULL; ++ err = grub_efi_get_ram_base (&max_addr); ++ if (err != GRUB_ERR_NONE) ++ { ++ grub_error (err, "grub_efi_get_ram_base() failed"); ++ return NULL; ++ } ++ ++ grub_dprintf ("linux", "max_addr: 0x%016lx, INITRD_MAX_ADDRESS_OFFSET: 0x%016llx\n", ++ max_addr, INITRD_MAX_ADDRESS_OFFSET); + + max_addr += INITRD_MAX_ADDRESS_OFFSET - 1; ++ grub_dprintf ("linux", "calling grub_efi_allocate_pages_real (0x%016lx, 0x%08x, EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_DATA)", max_addr, initrd_pages); + +- return grub_efi_allocate_pages_real (max_addr, initrd_pages, +- GRUB_EFI_ALLOCATE_MAX_ADDRESS, +- GRUB_EFI_LOADER_DATA); ++ ret = grub_efi_allocate_pages_real (max_addr, initrd_pages, ++ GRUB_EFI_ALLOCATE_MAX_ADDRESS, ++ GRUB_EFI_LOADER_DATA); ++ grub_dprintf ("linux", "got 0x%016llx\n", (unsigned long long)ret); ++ return ret; + } + #endif + +@@ -452,13 +677,55 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + return grub_errno; + } + ++#if !defined(__i386__) && !defined(__x86_64__) ++static grub_err_t ++parse_pe_header (void *kernel, grub_uint64_t *total_size, ++ grub_uint32_t *entry_offset, ++ grub_uint32_t *alignment, grub_uint32_t *code_size) ++{ ++ struct linux_arch_kernel_header *lh = kernel; ++ struct grub_armxx_linux_pe_header *pe; ++ grub_uint16_t i; ++ struct grub_pe32_section_table *sections; ++ ++ pe = (void *)((unsigned long)kernel + lh->hdr_offset); ++ ++ if (pe->opt.magic != GRUB_PE32_PEXX_MAGIC) ++ return grub_error(GRUB_ERR_BAD_OS, "Invalid PE optional header magic"); ++ ++ *total_size = pe->opt.image_size; ++ *entry_offset = pe->opt.entry_addr; ++ *alignment = pe->opt.section_alignment; ++ *code_size = pe->opt.section_alignment; ++ ++ sections = (struct grub_pe32_section_table *) ((char *)&pe->opt + ++ pe->coff.optional_header_size); ++ grub_dprintf ("linux", "num_sections : %d\n", pe->coff.num_sections ); ++ for (i = 0 ; i < pe->coff.num_sections; i++) ++ { ++ grub_dprintf ("linux", "raw_size : %lld\n", ++ (long long) sections[i].raw_data_size); ++ grub_dprintf ("linux", "virt_size : %lld\n", ++ (long long) sections[i].virtual_size); ++ *code_size += sections[i].raw_data_size; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++#endif ++ + static grub_err_t + grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { + grub_file_t file = 0; + struct linux_arch_kernel_header lh; ++ grub_off_t filelen; ++ grub_off_t filereadlen; ++ void *kernel = NULL; + grub_err_t err; ++ int nx_supported = 1; ++ int nx_required = 0; + + grub_dl_ref (my_mod); + +@@ -488,50 +755,84 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + if (!file) + goto fail; + +- kernel_size = grub_file_size (file); ++ filelen = grub_file_size (file); ++ kernel = grub_malloc(filelen); ++ if (!kernel) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel load buffer")); ++ goto fail; ++ } ++ ++ filereadlen = grub_file_read (file, kernel, filelen); ++ grub_dprintf ("linux", "filelen : %lld\n", (long long) filelen); ++ grub_dprintf ("linux", "filereadlen : %lld\n", (long long) filereadlen); ++ ++ if (filereadlen < filelen) ++ { ++ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), ++ argv[0]); ++ goto fail; ++ } + +- if (grub_arch_efi_linux_load_image_header (file, &lh) != GRUB_ERR_NONE) + #if !defined(__i386__) && !defined(__x86_64__) ++ if (grub_arch_efi_linux_load_image_header (file, &lh) != GRUB_ERR_NONE) + goto fail; + #else +- goto fallback; +- +- if (!initrd_use_loadfile2) ++ if (grub_arch_efi_linux_load_image_header (file, &lh) != GRUB_ERR_NONE || ++ !initrd_use_loadfile2) + { ++ /* We cannot use the legacy loader when NX is required */ ++ if (grub_efi_check_nx_required(&nx_required)) ++ goto fail; ++ + /* + * This is a EFI stub image but it is too old to implement the LoadFile2 + * based initrd loading scheme, and Linux/x86 does not support the DT + * based method either. So fall back to the x86-specific loader that + * enters Linux in EFI mode but without going through its EFI stub. + */ +-fallback: + grub_file_close (file); + return grub_cmd_linux_x86_legacy (cmd, argc, argv); + } + #endif + ++ ++#if !defined(__i386__) && !defined(__x86_64__) ++ grub_uint32_t align; ++ grub_uint32_t code_size; ++ if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align, &code_size) != GRUB_ERR_NONE) ++ goto fail; ++ grub_dprintf ("linux", "kernel mem size : %lld\n", (long long) kernel_size); ++ grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset); ++ grub_dprintf ("linux", "kernel alignment : 0x%x\n", align); ++ grub_dprintf ("linux", "kernel size : 0x%x\n", code_size); ++ ++ err = grub_efi_check_nx_image_support((grub_addr_t)kernel, filelen, &nx_supported); ++ if (err != GRUB_ERR_NONE) ++ goto fail; ++ + grub_loader_unset(); + +- grub_dprintf ("linux", "kernel file size: %lld\n", (long long) kernel_size); +- kernel_addr = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (kernel_size)); +- grub_dprintf ("linux", "kernel numpages: %lld\n", +- (long long) GRUB_EFI_BYTES_TO_PAGES (kernel_size)); +- if (!kernel_addr) ++ kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1); ++ kernel_alloc_addr = grub_efi_allocate_pages_real (GRUB_EFI_MAX_USABLE_ADDRESS, ++ kernel_alloc_pages, ++ GRUB_EFI_ALLOCATE_MAX_ADDRESS, ++ GRUB_EFI_LOADER_CODE); ++ grub_dprintf ("linux", "kernel numpages: %d\n", kernel_alloc_pages); ++ if (!kernel_alloc_addr) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto fail; + } +- +- grub_file_seek (file, 0); +- if (grub_file_read (file, kernel_addr, kernel_size) +- < (grub_int64_t) kernel_size) +- { +- if (!grub_errno) +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]); +- goto fail; +- } ++ kernel_addr = (void *)ALIGN_UP((grub_uint64_t)kernel_alloc_addr, align); + + grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); ++ grub_memcpy (kernel_addr, kernel, grub_min(code_size, kernel_size)); ++ if (kernel_size > code_size) ++ grub_memset ((char *)kernel_addr + code_size, 0, kernel_size - code_size); ++ grub_free(kernel); ++ kernel = NULL; ++#endif + + cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); + linux_args = grub_malloc (cmdline_size); +@@ -555,6 +856,9 @@ fallback: + } + + fail: ++ if (kernel) ++ grub_free (kernel); ++ + if (file) + grub_file_close (file); + +@@ -567,9 +871,8 @@ fail: + if (linux_args && !loaded) + grub_free (linux_args); + +- if (kernel_addr && !loaded) +- grub_efi_free_pages ((grub_addr_t) kernel_addr, +- GRUB_EFI_BYTES_TO_PAGES (kernel_size)); ++ if (kernel_alloc_addr && !loaded) ++ grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages); + + return grub_errno; + } +diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c +index 7de3f7f86..6feb0412c 100644 +--- a/grub-core/loader/emu/linux.c ++++ b/grub-core/loader/emu/linux.c +@@ -15,7 +15,6 @@ + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ +- + #include + #include + #include +@@ -33,6 +32,196 @@ static char *kernel_path; + static char *initrd_path; + static char *boot_cmdline; + ++static grub_err_t ++grub_switch_root (void) ++{ ++ char *tmp = NULL; ++ char *options_cmd = NULL; ++ char *options = NULL; ++ char *subvol = NULL; ++ char *root_uuid = NULL; ++ char *kernel_release = NULL; ++ grub_err_t rc = GRUB_ERR_NONE; ++ const char *subvol_param = "subvol="; ++ const char *kernel_release_prefix = "/boot/vmlinuz-"; ++ const char *root_prefix = "root="; ++ const char *systemctl[] = {"systemctl", "--force", "switch-root", "/sysroot", NULL}; ++ const char *mountrootfs[] = {"mount", root_uuid, "/sysroot", options_cmd, options, NULL}; ++ const char *unamer[] = {"uname", "-r", NULL}; ++ char *uname_buf = NULL; ++ int i = 0; ++ ++ /* Extract the kernel release tag from kernel_path */ ++ if (!kernel_path) ++ { ++ rc = GRUB_ERR_BAD_ARGUMENT; ++ grub_dprintf ("linux", "switch_root: No kernel_path found\n"); ++ goto out; ++ } ++ ++ if ((kernel_release = grub_xasprintf ("%s", (kernel_path + grub_strlen (kernel_release_prefix)))) == NULL) ++ { ++ grub_dprintf ("linux", "switch_root: Failed to allocate memory\n"); ++ rc = GRUB_ERR_BAD_ARGUMENT; ++ goto out; ++ } ++ ++ ++ /* Check for kernel mismatch */ ++ /* Retrieve the current kernel relase tag */ ++ grub_util_exec_redirect (unamer, NULL, "/tmp/version"); ++ ++ grub_file_t f = grub_file_open ("/tmp/version", GRUB_FILE_TYPE_FS_SEARCH); ++ ++ if (f == NULL) ++ { ++ grub_dprintf ("linux", "failed opening file.\n"); ++ rc = GRUB_ERR_FILE_NOT_FOUND; ++ goto out; ++ } ++ ++ if ((uname_buf = grub_malloc (f->size)) == NULL) ++ { ++ grub_dprintf ("linux", "switch_root: Failed to allocate memory\n"); ++ rc = GRUB_ERR_OUT_OF_MEMORY; ++ goto out; ++ } ++ ++ if (grub_file_read (f, uname_buf, f->size) < 0) ++ { ++ grub_dprintf ("linux", "switch_root: failed to read from file\n"); ++ rc = GRUB_ERR_FILE_READ_ERROR; ++ goto out; ++ } ++ ++ grub_file_close (f); ++ ++ if (grub_strstr (uname_buf, kernel_release) == NULL) ++ { ++ grub_dprintf ("linux", "switch_root: kernel mismatch, not performing switch-root ...\n"); ++ rc = GRUB_ERR_NO_KERNEL; ++ goto out; ++ } ++ ++ /* Extract the root partition from boot_cmdline */ ++ if (!boot_cmdline) ++ { ++ rc = GRUB_ERR_BAD_ARGUMENT; ++ goto out; ++ } ++ ++ tmp = grub_strdup (boot_cmdline); ++ ++ if (tmp == NULL) ++ { ++ rc = GRUB_ERR_OUT_OF_MEMORY; ++ goto out; ++ } ++ ++ if ((root_uuid = grub_strstr (tmp, root_prefix)) == NULL) ++ { ++ rc = GRUB_ERR_BAD_ARGUMENT; ++ grub_dprintf ("linux", "switch_root: Can't find rootfs\n"); ++ goto out; ++ } ++ ++ root_uuid += grub_strlen (root_prefix); ++ ++ while (root_uuid[i] != ' ' && root_uuid[i] != '\0') ++ i++; ++ ++ root_uuid[i] = '\0'; ++ ++ /* Allocate a new buffer holding root_uuid */ ++ root_uuid = grub_xasprintf ("%s", root_uuid); ++ ++ if (root_uuid == NULL) ++ { ++ grub_dprintf ("linux", "switch_root: Failed to allocated memory\n"); ++ rc = GRUB_ERR_OUT_OF_MEMORY; ++ goto out; ++ } ++ ++ /* Check for subvol parameter */ ++ grub_strcpy (tmp, boot_cmdline); ++ ++ if ((subvol = grub_strstr(tmp, subvol_param)) != NULL) ++ { ++ i = 0; ++ ++ while (subvol[i] != ' ' && subvol[i] != '\0') ++ i++; ++ ++ subvol[i] = '\0'; ++ ++ /* Allocate a new buffer holding subvol */ ++ subvol = grub_xasprintf("%s", subvol); ++ ++ if (subvol == NULL) ++ { ++ grub_dprintf ("linux", "switch_root: Failed to allocated memory\n"); ++ rc = GRUB_ERR_OUT_OF_MEMORY; ++ goto out; ++ } ++ ++ options_cmd = grub_xasprintf("%s", "-o"); ++ options = grub_xasprintf("%s", subvol); ++ } ++ ++ if (options == NULL) ++ { ++ mountrootfs[3] = NULL; ++ } ++ else ++ { ++ mountrootfs[3] = options_cmd; ++ mountrootfs[4] = options; ++ } ++ ++ mountrootfs[1] = root_uuid; ++ ++ grub_dprintf ("linux", "Executing:\n"); ++ grub_dprintf ("linux", "%s %s %s %s %s\n", mountrootfs[0], mountrootfs[1], ++ mountrootfs[2], mountrootfs[3], mountrootfs[4]); ++ ++ /* Mount the rootfs */ ++ rc = grub_util_exec (mountrootfs); ++ ++ if (rc != GRUB_ERR_NONE) ++ { ++ grub_dprintf ("linux", "switch_root: Failed.\n"); ++ rc = GRUB_ERR_INVALID_COMMAND; ++ goto out; ++ } ++ ++ grub_dprintf ("linux", "Done.\n"); ++ ++ grub_dprintf ("linux", "%s %s %s %s\n", systemctl[0], systemctl[1], ++ systemctl[2], systemctl[3]); ++ ++ /* Switch root */ ++ rc = grub_util_exec (systemctl); ++ ++ if (rc != GRUB_ERR_NONE) ++ { ++ grub_dprintf ("linux", "switch_root: Failed.\n"); ++ rc = GRUB_ERR_INVALID_COMMAND; ++ goto out; ++ } ++ ++ grub_dprintf ("linux", "Done.\n"); ++ ++out: ++ grub_free (tmp); ++ grub_free (options_cmd); ++ grub_free (options); ++ grub_free (subvol); ++ grub_free (root_uuid); ++ grub_free (uname_buf); ++ grub_free (kernel_release); ++ return rc; ++} ++ + static grub_err_t + grub_linux_boot (void) + { +@@ -51,12 +240,20 @@ grub_linux_boot (void) + else + initrd_param = grub_xasprintf ("%s", ""); + +- grub_dprintf ("linux", "%serforming 'kexec -la %s %s %s'\n", +- (kexecute) ? "P" : "Not p", +- kernel_path, initrd_param, boot_cmdline); ++ if (grub_util_get_switch_root() == 1) ++ { ++ rc = grub_switch_root(); ++ if (rc != GRUB_ERR_NONE) ++ grub_fatal (N_("Failed to execute switch_root\n")); ++ } ++ else if (kexecute) ++ { ++ grub_dprintf ("linux", "%serforming 'kexec -la %s %s %s'\n", ++ (kexecute) ? "P" : "Not p", ++ kernel_path, initrd_param, boot_cmdline); + +- if (kexecute) +- rc = grub_util_exec (kexec); ++ rc = grub_util_exec (kexec); ++ } + + grub_free (initrd_param); + +diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c +index 1f9128f6f..8075ac9b0 100644 +--- a/grub-core/loader/i386/bsd.c ++++ b/grub-core/loader/i386/bsd.c +@@ -40,6 +40,7 @@ + #ifdef GRUB_MACHINE_PCBIOS + #include + #endif ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -2137,6 +2138,9 @@ static grub_command_t cmd_netbsd_module_elf, cmd_openbsd_ramdisk; + + GRUB_MOD_INIT (bsd) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + /* Net and OpenBSD kernels are often compressed. */ + grub_dl_load ("gzio"); + +@@ -2176,6 +2180,9 @@ GRUB_MOD_INIT (bsd) + + GRUB_MOD_FINI (bsd) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + grub_unregister_extcmd (cmd_freebsd); + grub_unregister_extcmd (cmd_openbsd); + grub_unregister_extcmd (cmd_netbsd); +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +new file mode 100644 +index 000000000..abbf6b24f +--- /dev/null ++++ b/grub-core/loader/i386/efi/linux.c +@@ -0,0 +1,604 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2012 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_dl_t my_mod; ++ ++static grub_command_t cmd_linux, cmd_initrd; ++static grub_command_t cmd_linuxefi, cmd_initrdefi; ++ ++struct grub_linuxefi_context { ++ void *kernel_mem; ++ grub_uint64_t kernel_size; ++ grub_uint32_t handover_offset; ++ struct linux_kernel_params *params; ++ char *cmdline; ++ int nx_supported; ++ void *initrd_mem; ++}; ++ ++#define MIN(a, b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a < _b ? _a : _b; }) ++ ++#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) ++ ++typedef enum { ++ NO_MEM, ++ KERNEL_MEM, ++ INITRD_MEM, ++} kernel_alloc_purpose_t; ++ ++struct allocation_choice { ++ kernel_alloc_purpose_t purpose; ++ grub_efi_physical_address_t addr; ++ grub_efi_allocate_type_t alloc_type; ++}; ++ ++enum { ++ KERNEL_PREF_ADDRESS, ++ KERNEL_4G_LIMIT, ++ KERNEL_NO_LIMIT, ++ INITRD_MAX_ADDRESS, ++}; ++ ++static struct allocation_choice max_addresses[] = ++ { ++ /* the kernel overrides this one with pref_address and ++ * GRUB_EFI_ALLOCATE_ADDRESS */ ++ [KERNEL_PREF_ADDRESS] = ++ { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ /* If the flag in params is set, this one gets changed to be above 4GB. */ ++ [KERNEL_4G_LIMIT] = ++ { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ /* this one is always below 4GB, which we still *prefer* even if the flag ++ * is set. */ ++ [KERNEL_NO_LIMIT] = ++ { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ /* this is for the initrd */ ++ [INITRD_MAX_ADDRESS] = ++ { INITRD_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { NO_MEM, 0, 0 } ++ }; ++static struct allocation_choice saved_addresses[sizeof(max_addresses) / sizeof(max_addresses[0])]; ++ ++#define save_addresses() grub_memcpy(saved_addresses, max_addresses, sizeof(max_addresses)) ++#define restore_addresses() grub_memcpy(max_addresses, saved_addresses, sizeof(max_addresses)) ++ ++static inline void ++kernel_free(void *addr, grub_efi_uintn_t size) ++{ ++ if (addr && size) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)addr, ++ BYTES_TO_PAGES(size)); ++} ++ ++static void * ++kernel_alloc(kernel_alloc_purpose_t purpose, ++ grub_efi_uintn_t size, ++ grub_efi_memory_type_t memtype, ++ const char * const errmsg) ++{ ++ void *addr = 0; ++ unsigned int i; ++ grub_efi_physical_address_t prev_max = 0; ++ ++ for (i = 0; max_addresses[i].addr != 0 && addr == 0; i++) ++ { ++ grub_uint64_t max = max_addresses[i].addr; ++ grub_efi_uintn_t pages; ++ ++ if (purpose != max_addresses[i].purpose) ++ continue; ++ ++ /* ++ * When we're *not* loading the kernel, or >4GB allocations aren't ++ * supported, these entries are basically all the same, so don't re-try ++ * the same parameters. ++ */ ++ if (max == prev_max) ++ continue; ++ ++ pages = BYTES_TO_PAGES(size); ++ grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n", ++ (unsigned long)pages, (void *)(unsigned long)max); ++ size = pages * GRUB_EFI_PAGE_SIZE; ++ ++ prev_max = max; ++ addr = grub_efi_allocate_pages_real (max, pages, ++ max_addresses[i].alloc_type, ++ memtype); ++ if (addr) ++ { ++ grub_dprintf ("linux", "Allocated at %p\n", addr); ++ grub_update_mem_attrs ((grub_addr_t)addr, size, ++ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, ++ GRUB_MEM_ATTR_X); ++ } ++ } ++ ++ while (grub_error_pop ()) ++ { ++ ; ++ } ++ ++ if (addr == NULL) ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "%s", errmsg); ++ ++ return addr; ++} ++ ++static grub_err_t ++grub_linuxefi_boot (void *data) ++{ ++ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data; ++ ++ asm volatile ("cli"); ++ ++ return grub_efi_linux_boot ((grub_addr_t)context->kernel_mem, ++ context->kernel_size, ++ context->handover_offset, ++ context->params, ++ context->nx_supported); ++} ++ ++static grub_err_t ++grub_linuxefi_unload (void *data) ++{ ++ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data; ++ struct linux_kernel_params *params = context->params; ++ ++ grub_dl_unref (my_mod); ++ ++ kernel_free (context->initrd_mem, params->ramdisk_size); ++ kernel_free (context->cmdline, params->cmdline_size + 1); ++ kernel_free (context->kernel_mem, context->kernel_size); ++ kernel_free (params, sizeof(*params)); ++ cmd_initrd->data = 0; ++ cmd_initrdefi->data = 0; ++ grub_free (context); ++ ++ max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ ++ return GRUB_ERR_NONE; ++} ++ ++#define BOUNCE_BUFFER_MAX 0x1000000ull ++ ++static grub_ssize_t ++read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) ++{ ++ grub_ssize_t bufpos = 0; ++ static grub_size_t bbufsz = 0; ++ static char *bbuf = NULL; ++ ++ if (bbufsz == 0) ++ bbufsz = MIN(BOUNCE_BUFFER_MAX, len); ++ ++ while (!bbuf && bbufsz) ++ { ++ bbuf = grub_malloc(bbufsz); ++ if (!bbuf) ++ bbufsz >>= 1; ++ } ++ if (!bbuf) ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate bounce buffer")); ++ ++ while (bufpos < (long long)len) ++ { ++ grub_ssize_t sz; ++ ++ sz = grub_file_read (file, bbuf, MIN(bbufsz, len - bufpos)); ++ if (sz < 0) ++ return sz; ++ if (sz == 0) ++ break; ++ ++ grub_memcpy(bufp + bufpos, bbuf, sz); ++ bufpos += sz; ++ } ++ ++ return bufpos; ++} ++ ++#define LOW_U32(val) ((grub_uint32_t)(((grub_addr_t)(val)) & 0xffffffffull)) ++#define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull)) ++ ++static grub_err_t ++grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) ++{ ++ grub_file_t *files = 0; ++ int i, nfiles = 0; ++ grub_size_t size = 0; ++ grub_uint8_t *ptr; ++ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data; ++ struct linux_kernel_params *params; ++ void *initrd_mem = 0; ++ ++ if (argc == 0) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ goto fail; ++ } ++ ++ if (!context) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); ++ goto fail; ++ } ++ ++ params = context->params; ++ ++ files = grub_calloc (argc, sizeof (files[0])); ++ if (!files) ++ goto fail; ++ ++ for (i = 0; i < argc; i++) ++ { ++ files[i] = grub_file_open (argv[i], GRUB_FILE_TYPE_LINUX_INITRD | GRUB_FILE_TYPE_NO_DECOMPRESS); ++ if (! files[i]) ++ goto fail; ++ nfiles++; ++ if (grub_add (size, ALIGN_UP (grub_file_size (files[i]), 4), &size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ goto fail; ++ } ++ } ++ ++ grub_dprintf ("linux", "Trying to allocate initrd mem\n"); ++ initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_LOADER_DATA, ++ N_("can't allocate initrd")); ++ if (initrd_mem == NULL) ++ goto fail; ++ grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); ++ ++ params->ramdisk_size = LOW_U32(size); ++ params->ramdisk_image = LOW_U32(initrd_mem); ++#if defined(__x86_64__) ++ params->ext_ramdisk_size = HIGH_U32(size); ++ params->ext_ramdisk_image = HIGH_U32(initrd_mem); ++#endif ++ ++ ptr = initrd_mem; ++ ++ for (i = 0; i < nfiles; i++) ++ { ++ grub_ssize_t cursize = grub_file_size (files[i]); ++ if (read (files[i], ptr, cursize) != cursize) ++ { ++ if (!grub_errno) ++ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), ++ argv[i]); ++ goto fail; ++ } ++ ptr += cursize; ++ grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4)); ++ ptr += ALIGN_UP_OVERHEAD (cursize, 4); ++ } ++ ++ kernel_free(context->initrd_mem, params->ramdisk_size); ++ ++ context->initrd_mem = initrd_mem; ++ params->ramdisk_size = size; ++ ++ fail: ++ for (i = 0; i < nfiles; i++) ++ grub_file_close (files[i]); ++ grub_free (files); ++ ++ if (initrd_mem && grub_errno) ++ kernel_free (initrd_mem, size); ++ ++ return grub_errno; ++} ++ ++static grub_err_t ++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ grub_file_t file = 0; ++ struct linux_i386_kernel_header *lh = NULL; ++ grub_ssize_t start, filelen; ++ void *kernel = NULL; ++ int setup_header_end_offset; ++ void *kernel_mem = 0; ++ grub_uint64_t kernel_size = 0; ++ grub_uint32_t handover_offset; ++ struct linux_kernel_params *params = 0; ++ char *cmdline = 0; ++ int nx_supported = 1; ++ struct grub_linuxefi_context *context = 0; ++ grub_err_t err; ++ ++ grub_dl_ref (my_mod); ++ ++ if (argc == 0) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ goto fail; ++ } ++ ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); ++ if (! file) ++ goto fail; ++ ++ filelen = grub_file_size (file); ++ ++ kernel = grub_malloc(filelen); ++ if (!kernel) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); ++ goto fail; ++ } ++ ++ if (grub_file_read (file, kernel, filelen) != filelen) ++ { ++ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), ++ argv[0]); ++ goto fail; ++ } ++ ++ err = grub_efi_check_nx_image_support ((grub_addr_t)kernel, filelen, ++ &nx_supported); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ grub_dprintf ("linux", "nx is%s supported by this kernel\n", ++ nx_supported ? "" : " not"); ++ ++ lh = (struct linux_i386_kernel_header *)kernel; ++ grub_dprintf ("linux", "original lh is at %p\n", kernel); ++ ++ grub_dprintf ("linux", "checking lh->boot_flag\n"); ++ if (lh->boot_flag != grub_cpu_to_le16 (0xaa55)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number")); ++ goto fail; ++ } ++ ++ grub_dprintf ("linux", "checking lh->setup_sects\n"); ++ if (lh->setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors")); ++ goto fail; ++ } ++ ++ grub_dprintf ("linux", "checking lh->version\n"); ++ if (lh->version < grub_cpu_to_le16 (0x020b)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("kernel too old")); ++ goto fail; ++ } ++ ++ grub_dprintf ("linux", "checking lh->handover_offset\n"); ++ if (!lh->handover_offset) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover")); ++ goto fail; ++ } ++ ++#if defined(__x86_64__) ++ grub_dprintf ("linux", "checking lh->xloadflags\n"); ++ if (!(lh->xloadflags & LINUX_XLF_KERNEL_64)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support 64-bit CPUs")); ++ goto fail; ++ } ++#endif ++ ++#if defined(__i386__) ++ if ((lh->xloadflags & LINUX_XLF_KERNEL_64) && ++ !(lh->xloadflags & LINUX_XLF_EFI_HANDOVER_32)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, ++ N_("kernel doesn't support 32-bit handover")); ++ goto fail; ++ } ++#endif ++ ++ max_addresses[INITRD_MAX_ADDRESS].addr = lh->initrd_addr_max; ++#if defined(__x86_64__) ++ if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G) ++ { ++ grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n"); ++ max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_USABLE_ADDRESS; ++ max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_USABLE_ADDRESS; ++ } ++ else ++ { ++ grub_dprintf ("linux", "Loading kernel above 4GB is not supported\n"); ++ } ++#endif ++ ++ params = kernel_alloc (KERNEL_MEM, sizeof(*params), ++ GRUB_EFI_LOADER_DATA, ++ "cannot allocate kernel parameters"); ++ if (!params) ++ goto fail; ++ grub_dprintf ("linux", "params = %p\n", params); ++ ++ grub_memset (params, 0, sizeof(*params)); ++ ++ setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); ++ grub_dprintf ("linux", "copying %lu bytes from %p to %p\n", ++ (unsigned long) ++ MIN((grub_size_t)0x202+setup_header_end_offset, ++ sizeof (*params)) - 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ (grub_uint8_t *)params + 0x1f1); ++ grub_memcpy ((grub_uint8_t *)params + 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1); ++ ++ lh = (struct linux_i386_kernel_header *)params; ++ grub_dprintf ("linux", "new lh is at %p\n", lh); ++ ++ grub_dprintf ("linux", "setting up cmdline\n"); ++ cmdline = kernel_alloc (KERNEL_MEM, lh->cmdline_size + 1, ++ GRUB_EFI_LOADER_DATA, ++ N_("can't allocate cmdline")); ++ if (!cmdline) ++ goto fail; ++ grub_dprintf ("linux", "cmdline = %p\n", cmdline); ++ ++ grub_memcpy (cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); ++ grub_create_loader_cmdline (argc, argv, ++ cmdline + sizeof (LINUX_IMAGE) - 1, ++ lh->cmdline_size - (sizeof (LINUX_IMAGE) - 1), ++ GRUB_VERIFY_KERNEL_CMDLINE); ++ ++ grub_dprintf ("linux", "cmdline:%s\n", cmdline); ++ grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", ++ LOW_U32(cmdline)); ++ lh->cmd_line_ptr = LOW_U32(cmdline); ++#if defined(__x86_64__) ++ if ((grub_efi_uintn_t)cmdline > 0xffffffffull) ++ { ++ grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n", ++ HIGH_U32(cmdline)); ++ params->ext_cmd_line_ptr = HIGH_U32(cmdline); ++ } ++#endif ++ ++ handover_offset = lh->handover_offset; ++ grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset); ++ ++ start = (lh->setup_sects + 1) * 512; ++ ++ /* ++ * AFAICS >4GB for kernel *cannot* work because of params->code32_start being ++ * 32-bit and getting called unconditionally in head_64.S from either entry ++ * point. ++ * ++ * so nerf that out here... ++ */ ++ save_addresses(); ++ grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address); ++ if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS) ++ { ++ max_addresses[KERNEL_PREF_ADDRESS].addr = lh->pref_address; ++ max_addresses[KERNEL_PREF_ADDRESS].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; ++ } ++ max_addresses[KERNEL_4G_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ kernel_size = lh->init_size; ++ grub_dprintf ("linux", "Trying to allocate kernel mem\n"); ++ kernel_mem = kernel_alloc (KERNEL_MEM, kernel_size, ++ GRUB_EFI_LOADER_CODE, ++ N_("can't allocate kernel")); ++ restore_addresses(); ++ if (!kernel_mem) ++ goto fail; ++ grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); ++ ++ grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n", ++ LOW_U32(kernel_mem)); ++ lh->code32_start = LOW_U32(kernel_mem); ++ ++ grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); ++ ++ lh->type_of_loader = 0x6; ++ grub_dprintf ("linux", "setting lh->type_of_loader = 0x%02x\n", ++ lh->type_of_loader); ++ ++ params->ext_loader_type = 0; ++ params->ext_loader_ver = 2; ++ grub_dprintf ("linux", ++ "setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n", ++ params->ext_loader_type, params->ext_loader_ver); ++ ++ context = grub_zalloc (sizeof (*context)); ++ if (!context) ++ goto fail; ++ context->kernel_mem = kernel_mem; ++ context->kernel_size = kernel_size; ++ context->handover_offset = handover_offset; ++ context->params = params; ++ context->cmdline = cmdline; ++ context->nx_supported = nx_supported; ++ ++ grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0); ++ ++ cmd_initrd->data = context; ++ cmd_initrdefi->data = context; ++ ++ grub_file_close (file); ++ grub_free (kernel); ++ return 0; ++ ++fail: ++ if (file) ++ grub_file_close (file); ++ ++ grub_dl_unref (my_mod); ++ ++ max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ ++ if (lh) ++ kernel_free (cmdline, lh->cmdline_size + 1); ++ ++ kernel_free (kernel_mem, kernel_size); ++ kernel_free (params, sizeof(*params)); ++ ++ grub_free (context); ++ grub_free (kernel); ++ ++ return grub_errno; ++} ++ ++GRUB_MOD_INIT(linux) ++{ ++ cmd_linux = ++ grub_register_command ("linux", grub_cmd_linux, ++ 0, N_("Load Linux.")); ++ cmd_linuxefi = ++ grub_register_command ("linuxefi", grub_cmd_linux, ++ 0, N_("Load Linux.")); ++ cmd_initrd = ++ grub_register_command ("initrd", grub_cmd_initrd, ++ 0, N_("Load initrd.")); ++ cmd_initrdefi = ++ grub_register_command ("initrdefi", grub_cmd_initrd, ++ 0, N_("Load initrd.")); ++ my_mod = mod; ++} ++ ++GRUB_MOD_FINI(linux) ++{ ++ grub_unregister_command (cmd_linux); ++ grub_unregister_command (cmd_linuxefi); ++ grub_unregister_command (cmd_initrd); ++ grub_unregister_command (cmd_initrdefi); ++} +diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c +index 977757f2c..90121e9bc 100644 +--- a/grub-core/loader/i386/linux.c ++++ b/grub-core/loader/i386/linux.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -661,13 +662,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + { + grub_file_t file = 0; + struct linux_i386_kernel_header lh; ++ grub_uint8_t *linux_params_ptr; + grub_uint8_t setup_sects; +- grub_size_t real_size, prot_size, prot_file_size; ++ grub_size_t real_size, prot_size, prot_file_size, kernel_offset; + grub_ssize_t len; + int i; + grub_size_t align, min_align; + int relocatable; + grub_uint64_t preferred_address = GRUB_LINUX_BZIMAGE_ADDR; ++ grub_uint8_t *kernel = NULL; + + grub_dl_ref (my_mod); + +@@ -681,7 +684,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + if (! file) + goto fail; + +- if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) ++ len = grub_file_size (file); ++ kernel = grub_malloc (len); ++ if (!kernel) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); ++ goto fail; ++ } ++ ++ if (grub_file_read (file, kernel, len) != len) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +@@ -689,6 +700,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++ grub_memcpy (&lh, kernel, sizeof (lh)); ++ kernel_offset = sizeof (lh); ++ + if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55)) + { + grub_error (GRUB_ERR_BAD_OS, "invalid magic number"); +@@ -796,15 +810,18 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + /* We've already read lh so there is no need to read it second time. */ + len -= sizeof(lh); + +- if ((len > 0) && +- (grub_file_read (file, (char *) &linux_params + sizeof (lh), len) != len)) ++ linux_params_ptr = (void *)&linux_params; ++ if (len > 0) + { +- if (!grub_errno) +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +- argv[0]); +- goto fail; ++ grub_memcpy (linux_params_ptr + sizeof (lh), kernel + kernel_offset, len); ++ kernel_offset += len; + } + ++ grub_dprintf("efi", "setting attributes for %p (%zu bytes) to +rw-x\n", ++ &linux_params, sizeof (lh) + len); ++ grub_update_mem_attrs ((grub_addr_t)&linux_params, sizeof (lh) + len, ++ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, GRUB_MEM_ATTR_X); ++ + linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR; + linux_params.kernel_alignment = (1 << align); + linux_params.ps_mouse = linux_params.padding11 = 0; +@@ -865,7 +882,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + /* The other parameters are filled when booting. */ + +- grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE); ++ kernel_offset = real_size + GRUB_DISK_SECTOR_SIZE; + + grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n", + (unsigned) real_size, (unsigned) prot_size); +@@ -1019,9 +1036,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + + len = prot_file_size; +- if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno) +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +- argv[0]); ++ grub_memcpy (prot_mode_mem, kernel + kernel_offset, len); + + if (grub_errno == GRUB_ERR_NONE) + { +@@ -1032,6 +1047,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + fail: + ++ grub_free (kernel); ++ + if (file) + grub_file_close (file); + +@@ -1153,6 +1170,9 @@ static grub_command_t cmd_linux, cmd_initrd; + + GRUB_MOD_INIT(linux) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + cmd_linux = grub_register_command ("linux", grub_cmd_linux, + 0, N_("Load Linux.")); + cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, +@@ -1162,6 +1182,9 @@ GRUB_MOD_INIT(linux) + + GRUB_MOD_FINI(linux) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + grub_unregister_command (cmd_linux); + grub_unregister_command (cmd_initrd); + } +diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c +index 4adeee9ae..54a76504a 100644 +--- a/grub-core/loader/i386/pc/linux.c ++++ b/grub-core/loader/i386/pc/linux.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -124,13 +125,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_file_t file = 0; + struct linux_i386_kernel_header lh; + grub_uint8_t setup_sects; +- grub_size_t real_size; ++ grub_size_t real_size, kernel_offset = 0; + grub_ssize_t len; + int i; + char *grub_linux_prot_chunk; + int grub_linux_is_bzimage; + grub_addr_t grub_linux_prot_target; + grub_err_t err; ++ grub_uint8_t *kernel = NULL; + + grub_dl_ref (my_mod); + +@@ -144,7 +146,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + if (! file) + goto fail; + +- if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) ++ len = grub_file_size (file); ++ kernel = grub_malloc (len); ++ if (!kernel) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); ++ goto fail; ++ } ++ ++ if (grub_file_read (file, kernel, len) != len) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +@@ -152,6 +162,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++ grub_memcpy (&lh, kernel, sizeof (lh)); ++ kernel_offset = sizeof (lh); ++ + if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55)) + { + grub_error (GRUB_ERR_BAD_OS, "invalid magic number"); +@@ -320,13 +333,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_memmove (grub_linux_real_chunk, &lh, sizeof (lh)); + + len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh); +- if (grub_file_read (file, grub_linux_real_chunk + sizeof (lh), len) != len) +- { +- if (!grub_errno) +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +- argv[0]); +- goto fail; +- } ++ grub_memcpy (grub_linux_real_chunk + sizeof (lh), kernel + kernel_offset, ++ len); ++ kernel_offset += len; + + if (lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE) + || grub_le_to_cpu16 (lh.version) < 0x0200) +@@ -364,9 +373,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + + len = grub_linux16_prot_size; +- if (grub_file_read (file, grub_linux_prot_chunk, len) != len && !grub_errno) +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +- argv[0]); ++ grub_memcpy (grub_linux_prot_chunk, kernel + kernel_offset, len); ++ kernel_offset += len; + + if (grub_errno == GRUB_ERR_NONE) + { +@@ -376,6 +384,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + fail: + ++ grub_free (kernel); ++ + if (file) + grub_file_close (file); + +@@ -474,14 +484,23 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + return grub_errno; + } + +-static grub_command_t cmd_linux, cmd_initrd; ++static grub_command_t cmd_linux, cmd_linux16, cmd_initrd, cmd_initrd16; + + GRUB_MOD_INIT(linux16) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + cmd_linux = ++ grub_register_command ("linux", grub_cmd_linux, ++ 0, N_("Load Linux.")); ++ cmd_linux16 = + grub_register_command ("linux16", grub_cmd_linux, + 0, N_("Load Linux.")); + cmd_initrd = ++ grub_register_command ("initrd", grub_cmd_initrd, ++ 0, N_("Load initrd.")); ++ cmd_initrd16 = + grub_register_command ("initrd16", grub_cmd_initrd, + 0, N_("Load initrd.")); + my_mod = mod; +@@ -489,6 +508,11 @@ GRUB_MOD_INIT(linux16) + + GRUB_MOD_FINI(linux16) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + grub_unregister_command (cmd_linux); ++ grub_unregister_command (cmd_linux16); + grub_unregister_command (cmd_initrd); ++ grub_unregister_command (cmd_initrd16); + } +diff --git a/grub-core/loader/i386/pc/truecrypt.c b/grub-core/loader/i386/pc/truecrypt.c +index bae1ad031..7bf801603 100644 +--- a/grub-core/loader/i386/pc/truecrypt.c ++++ b/grub-core/loader/i386/pc/truecrypt.c +@@ -176,7 +176,7 @@ grub_cmd_truecrypt (grub_command_t cmd __attribute__ ((unused)), + + edx = (dh << 8) | grub_get_root_biosnumber (); + +- destaddr = ALIGN_DOWN (grub_min (0x90000, grub_mmap_get_lower ()) ++ destaddr = ALIGN_DOWN (grub_min (0x90000ull, grub_mmap_get_lower ()) + - truecryptmemsize, 64 * 1024); + + { +diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c +index 94be512c4..94c112a29 100644 +--- a/grub-core/loader/multiboot.c ++++ b/grub-core/loader/multiboot.c +@@ -50,6 +50,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -444,6 +445,9 @@ static grub_command_t cmd_multiboot, cmd_module; + + GRUB_MOD_INIT(multiboot) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + cmd_multiboot = + #ifdef GRUB_USE_MULTIBOOT2 + grub_register_command ("multiboot2", grub_cmd_multiboot, +@@ -464,6 +468,9 @@ GRUB_MOD_INIT(multiboot) + + GRUB_MOD_FINI(multiboot) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + grub_unregister_command (cmd_multiboot); + grub_unregister_command (cmd_module); + } +diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c +index 1edad0594..24480df50 100644 +--- a/grub-core/loader/multiboot_elfxx.c ++++ b/grub-core/loader/multiboot_elfxx.c +@@ -45,9 +45,7 @@ + #endif + + #include +- +-#define CONCAT(a,b) CONCAT_(a, b) +-#define CONCAT_(a,b) a ## b ++#include + + #pragma GCC diagnostic ignored "-Wcast-align" + +@@ -101,7 +99,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) + return err; + + /* FIXME: Should we support program headers at strange locations? */ +- phlimit = grub_min (MULTIBOOT_SEARCH, grub_file_size (mld->file)); ++ phlimit = grub_min ((grub_off_t)MULTIBOOT_SEARCH, grub_file_size (mld->file)); + if ((grub_off_t) ehdr->e_phoff + phnum * ehdr->e_phentsize > phlimit) + return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset"); + +diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c +index 4cca55df9..f76f511ac 100644 +--- a/grub-core/loader/xnu.c ++++ b/grub-core/loader/xnu.c +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -1497,6 +1498,9 @@ static grub_extcmd_t cmd_splash; + + GRUB_MOD_INIT(xnu) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + cmd_kernel = grub_register_command ("xnu_kernel", grub_cmd_xnu_kernel, 0, + N_("Load XNU image.")); + cmd_kernel64 = grub_register_command ("xnu_kernel64", grub_cmd_xnu_kernel64, +@@ -1540,6 +1544,9 @@ GRUB_MOD_INIT(xnu) + + GRUB_MOD_FINI(xnu) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + #ifndef GRUB_MACHINE_EMU + grub_unregister_command (cmd_resume); + #endif +diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c +index 1d367436c..7adeb7447 100644 +--- a/grub-core/net/arp.c ++++ b/grub-core/net/arp.c +@@ -31,22 +31,12 @@ enum + ARP_REPLY = 2 + }; + +-enum +- { +- /* IANA ARP constant to define hardware type as ethernet. */ +- GRUB_NET_ARPHRD_ETHERNET = 1 +- }; +- +-struct arppkt { ++struct arphdr { + grub_uint16_t hrd; + grub_uint16_t pro; + grub_uint8_t hln; + grub_uint8_t pln; + grub_uint16_t op; +- grub_uint8_t sender_mac[6]; +- grub_uint32_t sender_ip; +- grub_uint8_t recv_mac[6]; +- grub_uint32_t recv_ip; + } GRUB_PACKED; + + static int have_pending; +@@ -57,12 +47,16 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *proto_addr) + { + struct grub_net_buff nb; +- struct arppkt *arp_packet; ++ struct arphdr *arp_header; + grub_net_link_level_address_t target_mac_addr; + grub_err_t err; + int i; + grub_uint8_t *nbd; + grub_uint8_t arp_data[128]; ++ grub_uint8_t hln; ++ grub_uint8_t pln; ++ grub_uint8_t arp_packet_len; ++ grub_uint8_t *tmp_ptr; + + if (proto_addr->type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4) + return grub_error (GRUB_ERR_BUG, "unsupported address family"); +@@ -73,23 +67,39 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf, + grub_netbuff_clear (&nb); + grub_netbuff_reserve (&nb, 128); + +- err = grub_netbuff_push (&nb, sizeof (*arp_packet)); ++ hln = inf->card->default_address.len; ++ pln = sizeof (proto_addr->ipv4); ++ arp_packet_len = sizeof (*arp_header) + 2 * (hln + pln); ++ ++ err = grub_netbuff_push (&nb, arp_packet_len); + if (err) + return err; + +- arp_packet = (struct arppkt *) nb.data; +- arp_packet->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET); +- arp_packet->hln = 6; +- arp_packet->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP); +- arp_packet->pln = 4; +- arp_packet->op = grub_cpu_to_be16_compile_time (ARP_REQUEST); +- /* Sender hardware address. */ +- grub_memcpy (arp_packet->sender_mac, &inf->hwaddress.mac, 6); +- arp_packet->sender_ip = inf->address.ipv4; +- grub_memset (arp_packet->recv_mac, 0, 6); +- arp_packet->recv_ip = proto_addr->ipv4; +- /* Target protocol address */ +- grub_memset (&target_mac_addr.mac, 0xff, 6); ++ arp_header = (struct arphdr *) nb.data; ++ arp_header->hrd = grub_cpu_to_be16 (inf->card->default_address.type); ++ arp_header->hln = hln; ++ arp_header->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP); ++ arp_header->pln = pln; ++ arp_header->op = grub_cpu_to_be16_compile_time (ARP_REQUEST); ++ tmp_ptr = nb.data + sizeof (*arp_header); ++ ++ /* The source hardware address. */ ++ grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln); ++ tmp_ptr += hln; ++ ++ /* The source protocol address. */ ++ grub_memcpy (tmp_ptr, &inf->address.ipv4, pln); ++ tmp_ptr += pln; ++ ++ /* The target hardware address. */ ++ grub_memset (tmp_ptr, 0, hln); ++ tmp_ptr += hln; ++ ++ /* The target protocol address */ ++ grub_memcpy (tmp_ptr, &proto_addr->ipv4, pln); ++ tmp_ptr += pln; ++ ++ grub_memset (&target_mac_addr.mac, 0xff, hln); + + nbd = nb.data; + send_ethernet_packet (inf, &nb, target_mac_addr, GRUB_NET_ETHERTYPE_ARP); +@@ -114,30 +124,56 @@ grub_err_t + grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, + grub_uint16_t *vlantag) + { +- struct arppkt *arp_packet = (struct arppkt *) nb->data; ++ struct arphdr *arp_header = (struct arphdr *) nb->data; + grub_net_network_level_address_t sender_addr, target_addr; + grub_net_link_level_address_t sender_mac_addr; + struct grub_net_network_level_interface *inf; +- +- if (arp_packet->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP) +- || arp_packet->pln != 4 || arp_packet->hln != 6 +- || nb->tail - nb->data < (int) sizeof (*arp_packet)) ++ grub_uint16_t hw_type; ++ grub_uint8_t hln; ++ grub_uint8_t pln; ++ grub_uint8_t arp_packet_len; ++ grub_uint8_t *tmp_ptr; ++ ++ hw_type = card->default_address.type; ++ hln = card->default_address.len; ++ pln = sizeof(sender_addr.ipv4); ++ arp_packet_len = sizeof (*arp_header) + 2 * (pln + hln); ++ ++ if (arp_header->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP) ++ || arp_header->hrd != grub_cpu_to_be16 (hw_type) ++ || arp_header->hln != hln || arp_header->pln != pln ++ || nb->tail - nb->data < (int) arp_packet_len) { + return GRUB_ERR_NONE; ++ } + ++ tmp_ptr = nb->data + sizeof (*arp_header); ++ ++ /* The source hardware address. */ ++ sender_mac_addr.type = hw_type; ++ sender_mac_addr.len = hln; ++ grub_memcpy (sender_mac_addr.mac, tmp_ptr, hln); ++ tmp_ptr += hln; ++ ++ /* The source protocol address. */ + sender_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; +- target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; +- sender_addr.ipv4 = arp_packet->sender_ip; +- target_addr.ipv4 = arp_packet->recv_ip; + sender_addr.option = 0; + target_addr.option = 0; +- if (arp_packet->sender_ip == pending_req) +- have_pending = 1; + +- sender_mac_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (sender_mac_addr.mac, arp_packet->sender_mac, +- sizeof (sender_mac_addr.mac)); ++ grub_memcpy(&sender_addr.ipv4, tmp_ptr, pln); ++ tmp_ptr += pln; ++ + grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1); + ++ /* The target hardware address. */ ++ tmp_ptr += hln; ++ ++ /* The target protocol address. */ ++ target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; ++ grub_memcpy(&target_addr.ipv4, tmp_ptr, pln); ++ ++ if (sender_addr.ipv4 == pending_req) ++ have_pending = 1; ++ + FOR_NET_NETWORK_LEVEL_INTERFACES (inf) + { + /* Verify vlantag id */ +@@ -150,11 +186,11 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, + + /* Am I the protocol address target? */ + if (grub_net_addr_cmp (&inf->address, &target_addr) == 0 +- && arp_packet->op == grub_cpu_to_be16_compile_time (ARP_REQUEST)) ++ && arp_header->op == grub_cpu_to_be16_compile_time (ARP_REQUEST)) + { + grub_net_link_level_address_t target; + struct grub_net_buff nb_reply; +- struct arppkt *arp_reply; ++ struct arphdr *arp_reply; + grub_uint8_t arp_data[128]; + grub_err_t err; + +@@ -163,25 +199,39 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, + grub_netbuff_clear (&nb_reply); + grub_netbuff_reserve (&nb_reply, 128); + +- err = grub_netbuff_push (&nb_reply, sizeof (*arp_packet)); ++ err = grub_netbuff_push (&nb_reply, arp_packet_len); + if (err) + return err; + +- arp_reply = (struct arppkt *) nb_reply.data; ++ arp_reply = (struct arphdr *) nb_reply.data; + +- arp_reply->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET); ++ arp_reply->hrd = grub_cpu_to_be16 (hw_type); + arp_reply->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP); +- arp_reply->pln = 4; +- arp_reply->hln = 6; ++ arp_reply->pln = pln; ++ arp_reply->hln = hln; + arp_reply->op = grub_cpu_to_be16_compile_time (ARP_REPLY); +- arp_reply->sender_ip = arp_packet->recv_ip; +- arp_reply->recv_ip = arp_packet->sender_ip; +- arp_reply->hln = 6; +- +- target.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (target.mac, arp_packet->sender_mac, 6); +- grub_memcpy (arp_reply->sender_mac, inf->hwaddress.mac, 6); +- grub_memcpy (arp_reply->recv_mac, arp_packet->sender_mac, 6); ++ ++ tmp_ptr = nb_reply.data + sizeof (*arp_reply); ++ ++ /* The source hardware address. */ ++ grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln); ++ tmp_ptr += hln; ++ ++ /* The source protocol address. */ ++ grub_memcpy (tmp_ptr, &target_addr.ipv4, pln); ++ tmp_ptr += pln; ++ ++ /* The target hardware address. */ ++ grub_memcpy (tmp_ptr, sender_mac_addr.mac, hln); ++ tmp_ptr += hln; ++ ++ /* The target protocol address */ ++ grub_memcpy (tmp_ptr, &sender_addr.ipv4, pln); ++ tmp_ptr += pln; ++ ++ target.type = hw_type; ++ target.len = hln; ++ grub_memcpy (target.mac, sender_mac_addr.mac, hln); + + /* Change operation to REPLY and send packet */ + send_ethernet_packet (inf, &nb_reply, target, GRUB_NET_ETHERTYPE_ARP); +diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c +index abe45ef7b..9cbdc2264 100644 +--- a/grub-core/net/bootp.c ++++ b/grub-core/net/bootp.c +@@ -20,10 +20,103 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include ++#include ++ ++static int ++dissect_url (const char *url, char **proto, char **host, char **path) ++{ ++ const char *p, *ps; ++ grub_size_t l; ++ ++ *proto = *host = *path = NULL; ++ ps = p = url; ++ ++ while ((p = grub_strchr (p, ':'))) ++ { ++ if (grub_strlen (p) < sizeof ("://") - 1) ++ break; ++ if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0) ++ { ++ l = p - ps; ++ *proto = grub_malloc (l + 1); ++ if (!*proto) ++ { ++ grub_print_error (); ++ return 0; ++ } ++ ++ grub_memcpy (*proto, ps, l); ++ (*proto)[l] = '\0'; ++ p += sizeof ("://") - 1; ++ break; ++ } ++ ++p; ++ } ++ ++ if (!*proto) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url); ++ return 0; ++ } ++ ++ ps = p; ++ p = grub_strchr (p, '/'); ++ ++ if (!p) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ ++ l = p - ps; ++ ++ if (l > 2 && ps[0] == '[' && ps[l - 1] == ']') ++ { ++ *host = grub_malloc (l - 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps + 1, l - 2); ++ (*host)[l - 2] = 0; ++ } ++ else ++ { ++ *host = grub_malloc (l + 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps, l); ++ (*host)[l] = 0; ++ } ++ ++ *path = grub_strdup (p); ++ if (!*path) ++ { ++ grub_print_error (); ++ grub_free (*host); ++ grub_free (*proto); ++ *host = NULL; ++ *proto = NULL; ++ return 0; ++ } ++ return 1; ++} + + struct grub_dhcp_discover_options + { +@@ -233,11 +326,10 @@ grub_net_configure_by_dhcp_ack (const char *name, + int is_def, char **device, char **path) + { + grub_net_network_level_address_t addr; +- grub_net_link_level_address_t hwaddr; + struct grub_net_network_level_interface *inter; + int mask = -1; + char server_ip[sizeof ("xxx.xxx.xxx.xxx")]; +- const grub_uint8_t *opt; ++ const char *opt; + grub_uint8_t opt_len, overload = 0; + const char *boot_file = 0, *server_name = 0; + grub_size_t boot_file_len, server_name_len; +@@ -251,12 +343,8 @@ grub_net_configure_by_dhcp_ack (const char *name, + if (path) + *path = 0; + +- grub_memcpy (hwaddr.mac, bp->mac_addr, +- bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len +- : sizeof (hwaddr.mac)); +- hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- +- inter = grub_net_add_addr (name, card, &addr, &hwaddr, flags); ++ grub_dprintf("dhcp", "configuring dhcp for %s\n", name); ++ inter = grub_net_add_addr (name, card, &addr, &card->default_address, flags); + if (!inter) + return 0; + +@@ -414,6 +502,60 @@ grub_net_configure_by_dhcp_ack (const char *name, + if (opt && opt_len) + grub_env_set_net_property (name, "rootpath", (const char *) opt, opt_len); + ++ opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER, &opt_len); ++ if (opt && opt_len) ++ { ++ grub_env_set_net_property (name, "vendor_class_identifier", (const char *) opt, opt_len); ++ if (opt && grub_strcmp ((char *)opt, "HTTPClient") == 0) ++ { ++ char *proto, *ip, *pa; ++ ++ if (!dissect_url (bp->boot_file, &proto, &ip, &pa)) ++ return inter; ++ ++ grub_env_set_net_property (name, "boot_file", pa, grub_strlen (pa)); ++ if (is_def) ++ { ++ grub_net_default_server = grub_strdup (ip); ++ grub_env_set ("net_default_interface", name); ++ grub_env_export ("net_default_interface"); ++ } ++ if (device && !*device) ++ { ++ *device = grub_xasprintf ("%s,%s", proto, ip); ++ grub_print_error (); ++ } ++ if (path) ++ { ++ *path = grub_strdup (pa); ++ grub_print_error (); ++ if (*path) ++ { ++ char *slash; ++ slash = grub_strrchr (*path, '/'); ++ if (slash) ++ *slash = 0; ++ else ++ **path = 0; ++ } ++ } ++ grub_net_add_ipv4_local (inter, mask); ++ inter->dhcp_ack = grub_malloc (size); ++ if (inter->dhcp_ack) ++ { ++ grub_memcpy (inter->dhcp_ack, bp, size); ++ inter->dhcp_acklen = size; ++ } ++ else ++ grub_errno = GRUB_ERR_NONE; ++ ++ grub_free (proto); ++ grub_free (ip); ++ grub_free (pa); ++ return inter; ++ } ++ } ++ + opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_EXTENSIONS_PATH, &opt_len); + if (opt && opt_len) + grub_env_set_net_property (name, "extensionspath", (const char *) opt, opt_len); +@@ -568,7 +710,9 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) + grub_memset (pack, 0, sizeof (*pack)); + pack->opcode = 1; + pack->hw_type = 1; +- pack->hw_len = 6; ++ pack->hw_len = iface->hwaddress.len > 16 ? 0 ++ : iface->hwaddress.len; ++ + err = grub_get_datetime (&date); + if (err || !grub_datetime2unixtime (&date, &t)) + { +@@ -581,7 +725,7 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) + else + pack->ident = iface->xid; + +- grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, 6); ++ grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, pack->hw_len); + + err = grub_netbuff_push (nb, sizeof (*udph)); + if (err) +@@ -610,6 +754,584 @@ out: + return err; + } + ++/* The default netbuff size for sending DHCPv6 packets which should be ++ large enough to hold the information */ ++#define GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE 512 ++ ++struct grub_dhcp6_options ++{ ++ grub_uint8_t *client_duid; ++ grub_uint16_t client_duid_len; ++ grub_uint8_t *server_duid; ++ grub_uint16_t server_duid_len; ++ grub_uint32_t iaid; ++ grub_uint32_t t1; ++ grub_uint32_t t2; ++ grub_net_network_level_address_t *ia_addr; ++ grub_uint32_t preferred_lifetime; ++ grub_uint32_t valid_lifetime; ++ grub_net_network_level_address_t *dns_server_addrs; ++ grub_uint16_t num_dns_server; ++ char *boot_file_proto; ++ char *boot_file_server_ip; ++ char *boot_file_path; ++}; ++ ++typedef struct grub_dhcp6_options *grub_dhcp6_options_t; ++ ++struct grub_dhcp6_session ++{ ++ struct grub_dhcp6_session *next; ++ struct grub_dhcp6_session **prev; ++ grub_uint32_t iaid; ++ grub_uint32_t transaction_id:24; ++ grub_uint64_t start_time; ++ struct grub_net_dhcp6_option_duid_ll duid; ++ struct grub_net_network_level_interface *iface; ++ ++ /* The associated dhcpv6 options */ ++ grub_dhcp6_options_t adv; ++ grub_dhcp6_options_t reply; ++}; ++ ++typedef struct grub_dhcp6_session *grub_dhcp6_session_t; ++ ++typedef void (*dhcp6_option_hook_fn) (const struct grub_net_dhcp6_option *opt, void *data); ++ ++static void ++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, ++ dhcp6_option_hook_fn hook, void *hook_data); ++ ++static void ++parse_dhcp6_iaaddr (const struct grub_net_dhcp6_option *opt, void *data) ++{ ++ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t )data; ++ ++ grub_uint16_t code = grub_be_to_cpu16 (opt->code); ++ grub_uint16_t len = grub_be_to_cpu16 (opt->len); ++ ++ if (code == GRUB_NET_DHCP6_OPTION_IAADDR) ++ { ++ const struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ iaaddr = (const struct grub_net_dhcp6_option_iaaddr *)opt->data; ++ ++ if (len < sizeof (*iaaddr)) ++ { ++ grub_dprintf ("bootp", "DHCPv6: code %u with insufficient length %u\n", code, len); ++ return; ++ } ++ if (!dhcp6->ia_addr) ++ { ++ dhcp6->ia_addr = grub_malloc (sizeof(*dhcp6->ia_addr)); ++ dhcp6->ia_addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ dhcp6->ia_addr->ipv6[0] = grub_get_unaligned64 (iaaddr->addr); ++ dhcp6->ia_addr->ipv6[1] = grub_get_unaligned64 (iaaddr->addr + 8); ++ dhcp6->preferred_lifetime = grub_be_to_cpu32 (iaaddr->preferred_lifetime); ++ dhcp6->valid_lifetime = grub_be_to_cpu32 (iaaddr->valid_lifetime); ++ } ++ } ++} ++ ++static void ++parse_dhcp6_option (const struct grub_net_dhcp6_option *opt, void *data) ++{ ++ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t)data; ++ grub_uint16_t code = grub_be_to_cpu16 (opt->code); ++ grub_uint16_t len = grub_be_to_cpu16 (opt->len); ++ ++ switch (code) ++ { ++ case GRUB_NET_DHCP6_OPTION_CLIENTID: ++ ++ if (dhcp6->client_duid || !len) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 CLIENTID with length %u\n", len); ++ break; ++ } ++ dhcp6->client_duid = grub_malloc (len); ++ grub_memcpy (dhcp6->client_duid, opt->data, len); ++ dhcp6->client_duid_len = len; ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_SERVERID: ++ ++ if (dhcp6->server_duid || !len) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 SERVERID with length %u\n", len); ++ break; ++ } ++ dhcp6->server_duid = grub_malloc (len); ++ grub_memcpy (dhcp6->server_duid, opt->data, len); ++ dhcp6->server_duid_len = len; ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_IA_NA: ++ { ++ const struct grub_net_dhcp6_option_iana *ia_na; ++ grub_uint16_t data_len; ++ ++ if (dhcp6->iaid || len < sizeof (*ia_na)) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 IA_NA with length %u\n", len); ++ break; ++ } ++ ia_na = (const struct grub_net_dhcp6_option_iana *)opt->data; ++ dhcp6->iaid = grub_be_to_cpu32 (ia_na->iaid); ++ dhcp6->t1 = grub_be_to_cpu32 (ia_na->t1); ++ dhcp6->t2 = grub_be_to_cpu32 (ia_na->t2); ++ ++ data_len = len - sizeof (*ia_na); ++ if (data_len) ++ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)ia_na->data, data_len, parse_dhcp6_iaaddr, dhcp6); ++ } ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_DNS_SERVERS: ++ { ++ const grub_uint8_t *po; ++ grub_uint16_t ln; ++ grub_net_network_level_address_t *la; ++ ++ if (!len || len & 0xf) ++ { ++ grub_dprintf ("bootp", "Skip invalid length DHCPv6 DNS_SERVERS \n"); ++ break; ++ } ++ dhcp6->num_dns_server = ln = len >> 4; ++ dhcp6->dns_server_addrs = la = grub_zalloc (ln * sizeof (*la)); ++ ++ for (po = opt->data; ln > 0; po += 0x10, la++, ln--) ++ { ++ la->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ la->ipv6[0] = grub_get_unaligned64 (po); ++ la->ipv6[1] = grub_get_unaligned64 (po + 8); ++ la->option = DNS_OPTION_PREFER_IPV6; ++ } ++ } ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_BOOTFILE_URL: ++ dissect_url ((const char *)opt->data, ++ &dhcp6->boot_file_proto, ++ &dhcp6->boot_file_server_ip, ++ &dhcp6->boot_file_path); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static void ++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, dhcp6_option_hook_fn hook, void *hook_data) ++{ ++ while (size) ++ { ++ grub_uint16_t code, len; ++ ++ if (size < sizeof (*opt)) ++ { ++ grub_dprintf ("bootp", "DHCPv6: Options stopped with remaining size %" PRIxGRUB_SIZE "\n", size); ++ break; ++ } ++ size -= sizeof (*opt); ++ len = grub_be_to_cpu16 (opt->len); ++ code = grub_be_to_cpu16 (opt->code); ++ if (size < len) ++ { ++ grub_dprintf ("bootp", "DHCPv6: Options stopped at out of bound length %u for option %u\n", len, code); ++ break; ++ } ++ if (!len) ++ { ++ grub_dprintf ("bootp", "DHCPv6: Options stopped at zero length option %u\n", code); ++ break; ++ } ++ else ++ { ++ if (hook) ++ hook (opt, hook_data); ++ size -= len; ++ opt = (const struct grub_net_dhcp6_option *)((grub_uint8_t *)opt + len + sizeof (*opt)); ++ } ++ } ++} ++ ++static grub_dhcp6_options_t ++grub_dhcp6_options_get (const struct grub_net_dhcp6_packet *v6h, ++ grub_size_t size) ++{ ++ grub_dhcp6_options_t options; ++ ++ if (size < sizeof (*v6h)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small")); ++ return NULL; ++ } ++ ++ options = grub_zalloc (sizeof(*options)); ++ if (!options) ++ return NULL; ++ ++ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)v6h->dhcp_options, ++ size - sizeof (*v6h), parse_dhcp6_option, options); ++ ++ return options; ++} ++ ++static void ++grub_dhcp6_options_free (grub_dhcp6_options_t options) ++{ ++ if (options->client_duid) ++ grub_free (options->client_duid); ++ if (options->server_duid) ++ grub_free (options->server_duid); ++ if (options->ia_addr) ++ grub_free (options->ia_addr); ++ if (options->dns_server_addrs) ++ grub_free (options->dns_server_addrs); ++ if (options->boot_file_proto) ++ grub_free (options->boot_file_proto); ++ if (options->boot_file_server_ip) ++ grub_free (options->boot_file_server_ip); ++ if (options->boot_file_path) ++ grub_free (options->boot_file_path); ++ ++ grub_free (options); ++} ++ ++static grub_dhcp6_session_t grub_dhcp6_sessions; ++#define FOR_DHCP6_SESSIONS_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE (var, next, grub_dhcp6_sessions) ++#define FOR_DHCP6_SESSIONS(var) FOR_LIST_ELEMENTS (var, grub_dhcp6_sessions) ++ ++static void ++grub_net_configure_by_dhcp6_info (const char *name, ++ struct grub_net_card *card, ++ grub_dhcp6_options_t dhcp6, ++ int is_def, ++ int flags, ++ struct grub_net_network_level_interface **ret_inf) ++{ ++ grub_net_network_level_netaddress_t netaddr; ++ struct grub_net_network_level_interface *inf; ++ ++ if (dhcp6->ia_addr) ++ { ++ inf = grub_net_add_addr (name, card, dhcp6->ia_addr, &card->default_address, flags); ++ ++ netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ netaddr.ipv6.base[0] = dhcp6->ia_addr->ipv6[0]; ++ netaddr.ipv6.base[1] = 0; ++ netaddr.ipv6.masksize = 64; ++ grub_net_add_route (name, netaddr, inf); ++ ++ if (ret_inf) ++ *ret_inf = inf; ++ } ++ ++ if (dhcp6->dns_server_addrs) ++ { ++ grub_uint16_t i; ++ ++ for (i = 0; i < dhcp6->num_dns_server; ++i) ++ grub_net_add_dns_server (dhcp6->dns_server_addrs + i); ++ } ++ ++ if (dhcp6->boot_file_path) ++ grub_env_set_net_property (name, "boot_file", dhcp6->boot_file_path, ++ grub_strlen (dhcp6->boot_file_path)); ++ ++ if (is_def && dhcp6->boot_file_server_ip) ++ { ++ grub_net_default_server = grub_strdup (dhcp6->boot_file_server_ip); ++ grub_env_set ("net_default_interface", name); ++ grub_env_export ("net_default_interface"); ++ } ++} ++ ++static void ++grub_dhcp6_session_add (struct grub_net_network_level_interface *iface, ++ grub_uint32_t iaid) ++{ ++ grub_dhcp6_session_t se; ++ struct grub_datetime date; ++ grub_err_t err; ++ grub_int64_t t = 0; ++ ++ se = grub_malloc (sizeof (*se)); ++ ++ err = grub_get_datetime (&date); ++ if (err || !grub_datetime2unixtime (&date, &t)) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ t = 0; ++ } ++ ++ se->iface = iface; ++ se->iaid = iaid; ++ se->transaction_id = t; ++ se->start_time = grub_get_time_ms (); ++ se->duid.type = grub_cpu_to_be16_compile_time (3) ; ++ se->duid.hw_type = grub_cpu_to_be16_compile_time (1); ++ grub_memcpy (&se->duid.hwaddr, &iface->hwaddress.mac, sizeof (se->duid.hwaddr)); ++ se->adv = NULL; ++ se->reply = NULL; ++ grub_list_push (GRUB_AS_LIST_P (&grub_dhcp6_sessions), GRUB_AS_LIST (se)); ++} ++ ++static void ++grub_dhcp6_session_remove (grub_dhcp6_session_t se) ++{ ++ grub_list_remove (GRUB_AS_LIST (se)); ++ if (se->adv) ++ grub_dhcp6_options_free (se->adv); ++ if (se->reply) ++ grub_dhcp6_options_free (se->reply); ++ grub_free (se); ++} ++ ++static void ++grub_dhcp6_session_remove_all (void) ++{ ++ grub_dhcp6_session_t se, next; ++ ++ FOR_DHCP6_SESSIONS_SAFE (se, next) ++ { ++ grub_dhcp6_session_remove (se); ++ } ++ grub_dhcp6_sessions = NULL; ++} ++ ++static grub_err_t ++grub_dhcp6_session_configure_network (grub_dhcp6_session_t se) ++{ ++ char *name; ++ ++ name = grub_xasprintf ("%s:dhcp6", se->iface->card->name); ++ if (!name) ++ return grub_errno; ++ ++ grub_net_configure_by_dhcp6_info (name, se->iface->card, se->reply, 1, 0, 0); ++ grub_free (name); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_dhcp6_session_send_request (grub_dhcp6_session_t se) ++{ ++ struct grub_net_buff *nb; ++ struct grub_net_dhcp6_option *opt; ++ struct grub_net_dhcp6_packet *v6h; ++ struct grub_net_dhcp6_option_iana *ia_na; ++ struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ struct udphdr *udph; ++ grub_net_network_level_address_t multicast; ++ grub_net_link_level_address_t ll_multicast; ++ grub_uint64_t elapsed; ++ struct grub_net_network_level_interface *inf = se->iface; ++ grub_dhcp6_options_t dhcp6 = se->adv; ++ grub_err_t err = GRUB_ERR_NONE; ++ ++ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48); ++ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL); ++ ++ err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast); ++ if (err) ++ return err; ++ ++ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ ++ if (!nb) ++ return grub_errno; ++ ++ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ err = grub_netbuff_push (nb, dhcp6->client_duid_len + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID); ++ opt->len = grub_cpu_to_be16 (dhcp6->client_duid_len); ++ grub_memcpy (opt->data, dhcp6->client_duid , dhcp6->client_duid_len); ++ ++ err = grub_netbuff_push (nb, dhcp6->server_duid_len + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_SERVERID); ++ opt->len = grub_cpu_to_be16 (dhcp6->server_duid_len); ++ grub_memcpy (opt->data, dhcp6->server_duid , dhcp6->server_duid_len); ++ ++ err = grub_netbuff_push (nb, sizeof (*ia_na) + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ if (dhcp6->ia_addr) ++ { ++ err = grub_netbuff_push (nb, sizeof(*iaaddr) + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ } ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); ++ opt->len = grub_cpu_to_be16 (sizeof (*ia_na)); ++ if (dhcp6->ia_addr) ++ opt->len += grub_cpu_to_be16 (sizeof(*iaaddr) + sizeof (*opt)); ++ ++ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data; ++ ia_na->iaid = grub_cpu_to_be32 (dhcp6->iaid); ++ ++ ia_na->t1 = grub_cpu_to_be32 (dhcp6->t1); ++ ia_na->t2 = grub_cpu_to_be32 (dhcp6->t2); ++ ++ if (dhcp6->ia_addr) ++ { ++ opt = (struct grub_net_dhcp6_option *)ia_na->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR); ++ opt->len = grub_cpu_to_be16 (sizeof (*iaaddr)); ++ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)opt->data; ++ grub_set_unaligned64 (iaaddr->addr, dhcp6->ia_addr->ipv6[0]); ++ grub_set_unaligned64 (iaaddr->addr + 8, dhcp6->ia_addr->ipv6[1]); ++ ++ iaaddr->preferred_lifetime = grub_cpu_to_be32 (dhcp6->preferred_lifetime); ++ iaaddr->valid_lifetime = grub_cpu_to_be32 (dhcp6->valid_lifetime); ++ } ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + 2 * sizeof (grub_uint16_t)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option*) nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ORO); ++ opt->len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_uint16_t)); ++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL)); ++ grub_set_unaligned16 (opt->data + 2, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS)); ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ opt = (struct grub_net_dhcp6_option*) nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t)); ++ ++ /* the time is expressed in hundredths of a second */ ++ elapsed = grub_divmod64 (grub_get_time_ms () - se->start_time, 10, 0); ++ ++ if (elapsed > 0xffff) ++ elapsed = 0xffff; ++ ++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16 ((grub_uint16_t)elapsed)); ++ ++ err = grub_netbuff_push (nb, sizeof (*v6h)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ v6h = (struct grub_net_dhcp6_packet *) nb->data; ++ v6h->message_type = GRUB_NET_DHCP6_REQUEST; ++ v6h->transaction_id = se->transaction_id; ++ ++ err = grub_netbuff_push (nb, sizeof (*udph)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ udph = (struct udphdr *) nb->data; ++ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT); ++ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT); ++ udph->chksum = 0; ++ udph->len = grub_cpu_to_be16 (nb->tail - nb->data); ++ ++ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, ++ &inf->address, ++ &multicast); ++ err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb, ++ GRUB_NET_IP_UDP); ++ ++ grub_netbuff_free (nb); ++ ++ return err; ++} ++ ++struct grub_net_network_level_interface * ++grub_net_configure_by_dhcpv6_reply (const char *name, ++ struct grub_net_card *card, ++ grub_net_interface_flags_t flags, ++ const struct grub_net_dhcp6_packet *v6h, ++ grub_size_t size, ++ int is_def, ++ char **device, char **path) ++{ ++ struct grub_net_network_level_interface *inf; ++ grub_dhcp6_options_t dhcp6; ++ int mask = -1; ++ ++ dhcp6 = grub_dhcp6_options_get (v6h, size); ++ if (!dhcp6) ++ { ++ grub_print_error (); ++ return NULL; ++ } ++ ++ grub_net_configure_by_dhcp6_info (name, card, dhcp6, is_def, flags, &inf); ++ ++ if (device && dhcp6->boot_file_proto && dhcp6->boot_file_server_ip) ++ { ++ *device = grub_xasprintf ("%s,%s", dhcp6->boot_file_proto, dhcp6->boot_file_server_ip); ++ grub_print_error (); ++ } ++ if (path && dhcp6->boot_file_path) ++ { ++ *path = grub_strdup (dhcp6->boot_file_path); ++ grub_print_error (); ++ if (*path) ++ { ++ char *slash; ++ slash = grub_strrchr (*path, '/'); ++ if (slash) ++ *slash = 0; ++ else ++ **path = 0; ++ } ++ } ++ ++ grub_dhcp6_options_free (dhcp6); ++ ++ if (inf) ++ grub_net_add_ipv6_local (inf, mask); ++ ++ return inf; ++} ++ + /* + * This is called directly from net/ip.c:handle_dgram(), because those + * BOOTP/DHCP packets are a bit special due to their improper +@@ -678,6 +1400,77 @@ grub_net_process_dhcp (struct grub_net_buff *nb, + } + } + ++grub_err_t ++grub_net_process_dhcp6 (struct grub_net_buff *nb, ++ struct grub_net_card *card __attribute__ ((unused))) ++{ ++ const struct grub_net_dhcp6_packet *v6h; ++ grub_dhcp6_session_t se; ++ grub_size_t size; ++ grub_dhcp6_options_t options; ++ ++ v6h = (const struct grub_net_dhcp6_packet *) nb->data; ++ size = nb->tail - nb->data; ++ ++ options = grub_dhcp6_options_get (v6h, size); ++ if (!options) ++ return grub_errno; ++ ++ if (!options->client_duid || !options->server_duid || !options->ia_addr) ++ { ++ grub_dhcp6_options_free (options); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Bad DHCPv6 Packet"); ++ } ++ ++ FOR_DHCP6_SESSIONS (se) ++ { ++ if (se->transaction_id == v6h->transaction_id && ++ grub_memcmp (options->client_duid, &se->duid, sizeof (se->duid)) == 0 && ++ se->iaid == options->iaid) ++ break; ++ } ++ ++ if (!se) ++ { ++ grub_dprintf ("bootp", "DHCPv6 session not found\n"); ++ grub_dhcp6_options_free (options); ++ return GRUB_ERR_NONE; ++ } ++ ++ if (v6h->message_type == GRUB_NET_DHCP6_ADVERTISE) ++ { ++ if (se->adv) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 Advertised .. \n"); ++ grub_dhcp6_options_free (options); ++ return GRUB_ERR_NONE; ++ } ++ ++ se->adv = options; ++ return grub_dhcp6_session_send_request (se); ++ } ++ else if (v6h->message_type == GRUB_NET_DHCP6_REPLY) ++ { ++ if (!se->adv) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 Reply .. \n"); ++ grub_dhcp6_options_free (options); ++ return GRUB_ERR_NONE; ++ } ++ ++ se->reply = options; ++ grub_dhcp6_session_configure_network (se); ++ grub_dhcp6_session_remove (se); ++ return GRUB_ERR_NONE; ++ } ++ else ++ { ++ grub_dhcp6_options_free (options); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ + static grub_err_t + grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +@@ -903,7 +1696,174 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), + return err; + } + +-static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp; ++static grub_err_t ++grub_cmd_bootp6 (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, char **args) ++{ ++ struct grub_net_card *card; ++ grub_uint32_t iaid = 0; ++ int interval; ++ grub_err_t err; ++ grub_dhcp6_session_t se; ++ ++ err = GRUB_ERR_NONE; ++ ++ FOR_NET_CARDS (card) ++ { ++ struct grub_net_network_level_interface *iface; ++ ++ if (argc > 0 && grub_strcmp (card->name, args[0]) != 0) ++ continue; ++ ++ iface = grub_net_ipv6_get_link_local (card, &card->default_address); ++ if (!iface) ++ { ++ grub_dhcp6_session_remove_all (); ++ return grub_errno; ++ } ++ ++ grub_dhcp6_session_add (iface, iaid++); ++ } ++ ++ for (interval = 200; interval < 10000; interval *= 2) ++ { ++ int done = 1; ++ ++ FOR_DHCP6_SESSIONS (se) ++ { ++ struct grub_net_buff *nb; ++ struct grub_net_dhcp6_option *opt; ++ struct grub_net_dhcp6_packet *v6h; ++ struct grub_net_dhcp6_option_duid_ll *duid; ++ struct grub_net_dhcp6_option_iana *ia_na; ++ grub_net_network_level_address_t multicast; ++ grub_net_link_level_address_t ll_multicast; ++ struct udphdr *udph; ++ ++ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48); ++ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL); ++ ++ err = grub_net_link_layer_resolve (se->iface, ++ &multicast, &ll_multicast); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ return err; ++ } ++ ++ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ ++ if (!nb) ++ { ++ grub_dhcp6_session_remove_all (); ++ return grub_errno; ++ } ++ ++ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t)); ++ grub_set_unaligned16 (opt->data, 0); ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*duid)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID); ++ opt->len = grub_cpu_to_be16 (sizeof (*duid)); ++ ++ duid = (struct grub_net_dhcp6_option_duid_ll *) opt->data; ++ grub_memcpy (duid, &se->duid, sizeof (*duid)); ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*ia_na)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); ++ opt->len = grub_cpu_to_be16 (sizeof (*ia_na)); ++ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data; ++ ia_na->iaid = grub_cpu_to_be32 (se->iaid); ++ ia_na->t1 = 0; ++ ia_na->t2 = 0; ++ ++ err = grub_netbuff_push (nb, sizeof (*v6h)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ v6h = (struct grub_net_dhcp6_packet *)nb->data; ++ v6h->message_type = GRUB_NET_DHCP6_SOLICIT; ++ v6h->transaction_id = se->transaction_id; ++ ++ grub_netbuff_push (nb, sizeof (*udph)); ++ ++ udph = (struct udphdr *) nb->data; ++ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT); ++ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT); ++ udph->chksum = 0; ++ udph->len = grub_cpu_to_be16 (nb->tail - nb->data); ++ ++ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, ++ &se->iface->address, &multicast); ++ ++ err = grub_net_send_ip_packet (se->iface, &multicast, ++ &ll_multicast, nb, GRUB_NET_IP_UDP); ++ done = 0; ++ grub_netbuff_free (nb); ++ ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ return err; ++ } ++ } ++ if (!done) ++ grub_net_poll_cards (interval, 0); ++ } ++ ++ FOR_DHCP6_SESSIONS (se) ++ { ++ grub_error_push (); ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, ++ N_("couldn't autoconfigure %s"), ++ se->iface->card->name); ++ } ++ ++ grub_dhcp6_session_remove_all (); ++ ++ return err; ++} ++ ++static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp, cmd_bootp6; + + void + grub_bootp_init (void) +@@ -917,11 +1877,15 @@ grub_bootp_init (void) + cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt, + N_("VAR INTERFACE NUMBER DESCRIPTION"), + N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value.")); ++ cmd_bootp6 = grub_register_command ("net_bootp6", grub_cmd_bootp6, ++ N_("[CARD]"), ++ N_("perform a DHCPv6 autoconfiguration")); + } + + void + grub_bootp_fini (void) + { ++ grub_unregister_command (cmd_bootp6); + grub_unregister_command (cmd_getdhcp); + grub_unregister_command (cmd_bootp); + grub_unregister_command (cmd_dhcp); +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 3ea25cf98..4591d0757 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -18,17 +18,24 @@ + + #include + #include ++#include + #include + #include + #include + #include + #include ++#include ++#include ++#include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + + /* GUID. */ + static grub_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID; + static grub_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; ++static grub_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID; ++static grub_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID; + + static grub_err_t + send_card_buffer (struct grub_net_card *dev, +@@ -285,6 +292,9 @@ grub_efinet_findcards (void) + /* This should not happen... Why? */ + continue; + ++ if (net->mode->hwaddr_size > GRUB_NET_MAX_LINK_ADDRESS_SIZE) ++ continue; ++ + if (net->mode->state == GRUB_EFI_NETWORK_STOPPED + && net->start (net) != GRUB_EFI_SUCCESS) + continue; +@@ -329,10 +339,11 @@ grub_efinet_findcards (void) + * such as LoadFile2 for initrd loading. + */ + card->flags = GRUB_NET_CARD_NO_CLOSE_ON_FINI_HW; +- card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ card->default_address.type = net->mode->if_type; ++ card->default_address.len = net->mode->hwaddr_size; + grub_memcpy (card->default_address.mac, + net->mode->current_address, +- sizeof (card->default_address.mac)); ++ net->mode->hwaddr_size); + card->efi_net = net; + card->efi_handle = *handle; + +@@ -341,12 +352,405 @@ grub_efinet_findcards (void) + grub_free (handles); + } + ++static grub_efi_handle_t ++grub_efi_locate_device_path (grub_guid_t *protocol, grub_efi_device_path_t *device_path, ++ grub_efi_device_path_t **r_device_path) ++{ ++ grub_efi_handle_t handle; ++ grub_efi_status_t status; ++ ++ status = grub_efi_system_table->boot_services->locate_device_path( ++ protocol, &device_path, &handle); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ if (r_device_path) ++ *r_device_path = device_path; ++ ++ return handle; ++} ++ ++static grub_efi_ipv4_address_t * ++grub_dns_server_ip4_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns) ++{ ++ grub_efi_handle_t hnd; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_protocol_t *conf; ++ grub_efi_ipv4_address_t *addrs; ++ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv4_address_t); ++ ++ hnd = grub_efi_locate_device_path (&ip4_config_guid, dp, NULL); ++ ++ if (!hnd) ++ return 0; ++ ++ conf = grub_efi_open_protocol (hnd, &ip4_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ if (!conf) ++ return 0; ++ ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = conf->get_data(conf, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (addrs); ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = conf->get_data(conf, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (addrs); ++ return 0; ++ } ++ ++ *num_dns = data_size / sizeof (grub_efi_ipv4_address_t); ++ return addrs; ++} ++ ++static grub_efi_ipv6_address_t * ++grub_dns_server_ip6_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns) ++{ ++ grub_efi_handle_t hnd; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_protocol_t *conf; ++ grub_efi_ipv6_address_t *addrs; ++ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv6_address_t); ++ ++ hnd = grub_efi_locate_device_path (&ip6_config_guid, dp, NULL); ++ ++ if (!hnd) ++ return 0; ++ ++ conf = grub_efi_open_protocol (hnd, &ip6_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ if (!conf) ++ return 0; ++ ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = conf->get_data(conf, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (addrs); ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = conf->get_data(conf, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (addrs); ++ return 0; ++ } ++ ++ *num_dns = data_size / sizeof (grub_efi_ipv6_address_t); ++ return addrs; ++} ++ ++static struct grub_net_buff * ++grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6) ++{ ++ grub_efi_uint16_t uri_len; ++ grub_efi_device_path_t *ldp, *ddp; ++ grub_efi_uri_device_path_t *uri_dp; ++ struct grub_net_buff *nb; ++ grub_err_t err; ++ ++ ddp = grub_efi_duplicate_device_path (dp); ++ if (!ddp) ++ return NULL; ++ ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ uri_len = GRUB_EFI_DEVICE_PATH_LENGTH (ldp) > 4 ? GRUB_EFI_DEVICE_PATH_LENGTH (ldp) - 4 : 0; ++ ++ if (!uri_len) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ uri_dp = (grub_efi_uri_device_path_t *) ldp; ++ ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ /* Skip the DNS Device */ ++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE) ++ { ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ ++ ldp = grub_efi_find_last_device_path (ddp); ++ } ++ ++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ nb = grub_netbuff_alloc (512); ++ if (!nb) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp; ++ struct grub_net_bootp_packet *bp; ++ grub_uint8_t *ptr; ++ grub_efi_ipv4_address_t *dns; ++ grub_efi_uintn_t num_dns; ++ ++ bp = (struct grub_net_bootp_packet *) nb->tail; ++ err = grub_netbuff_put (nb, sizeof (*bp) + 4); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ ++ if (sizeof(bp->boot_file) < uri_len) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ grub_memcpy (bp->boot_file, uri_dp->uri, uri_len); ++ grub_memcpy (&bp->your_ip, ipv4->local_ip_address, sizeof (bp->your_ip)); ++ grub_memcpy (&bp->server_ip, ipv4->remote_ip_address, sizeof (bp->server_ip)); ++ ++ bp->vendor[0] = GRUB_NET_BOOTP_RFC1048_MAGIC_0; ++ bp->vendor[1] = GRUB_NET_BOOTP_RFC1048_MAGIC_1; ++ bp->vendor[2] = GRUB_NET_BOOTP_RFC1048_MAGIC_2; ++ bp->vendor[3] = GRUB_NET_BOOTP_RFC1048_MAGIC_3; ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, sizeof (ipv4->subnet_mask) + 2); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_NETMASK; ++ *ptr++ = sizeof (ipv4->subnet_mask); ++ grub_memcpy (ptr, ipv4->subnet_mask, sizeof (ipv4->subnet_mask)); ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, sizeof (ipv4->gateway_ip_address) + 2); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_ROUTER; ++ *ptr++ = sizeof (ipv4->gateway_ip_address); ++ grub_memcpy (ptr, ipv4->gateway_ip_address, sizeof (ipv4->gateway_ip_address)); ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, sizeof ("HTTPClient") + 1); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER; ++ *ptr++ = sizeof ("HTTPClient") - 1; ++ grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1); ++ ++ dns = grub_dns_server_ip4_address (dp, &num_dns); ++ if (dns) ++ { ++ grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns; ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, size_dns + 2); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_DNS; ++ *ptr++ = size_dns; ++ grub_memcpy (ptr, dns, size_dns); ++ grub_free (dns); ++ } ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, 1); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr = GRUB_NET_BOOTP_END; ++ *use_ipv6 = 0; ++ ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_mac_address_device_path_t *mac = (grub_efi_mac_address_device_path_t *) ldp; ++ bp->hw_type = mac->if_type; ++ bp->hw_len = sizeof (bp->mac_addr); ++ grub_memcpy (bp->mac_addr, mac->mac_address, bp->hw_len); ++ } ++ } ++ else ++ { ++ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) ldp; ++ ++ struct grub_net_dhcp6_packet *d6p; ++ struct grub_net_dhcp6_option *opt; ++ struct grub_net_dhcp6_option_iana *iana; ++ struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ grub_efi_ipv6_address_t *dns; ++ grub_efi_uintn_t num_dns; ++ ++ d6p = (struct grub_net_dhcp6_packet *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*d6p)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ d6p->message_type = GRUB_NET_DHCP6_REPLY; ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof(*iana) + sizeof(*opt) + sizeof(*iaaddr)); ++ ++ err = grub_netbuff_put (nb, sizeof(*iana)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof (*iaaddr)); ++ ++ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*iaaddr)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ grub_memcpy (iaaddr->addr, ipv6->local_ip_address, sizeof(ipv6->local_ip_address)); ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt) + uri_len); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL); ++ opt->len = grub_cpu_to_be16 (uri_len); ++ grub_memcpy (opt->data, uri_dp->uri, uri_len); ++ ++ dns = grub_dns_server_ip6_address (dp, &num_dns); ++ if (dns) ++ { ++ grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns; ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt) + size_dns); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS); ++ opt->len = grub_cpu_to_be16 (size_dns); ++ grub_memcpy (opt->data, dns, size_dns); ++ grub_free (dns); ++ } ++ ++ *use_ipv6 = 1; ++ } ++ ++ grub_free (ddp); ++ return nb; ++} ++ + static void + grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + char **path) + { + struct grub_net_card *card; +- grub_efi_device_path_t *dp; ++ grub_efi_device_path_t *dp, *ldp = NULL; + struct grub_net_network_level_interface *inter; + grub_efi_device_path_t *vlan_dp; + grub_efi_uint16_t vlan_dp_len; +@@ -360,15 +764,24 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + { + grub_efi_device_path_t *cdp; + struct grub_efi_pxe *pxe; +- struct grub_efi_pxe_mode *pxe_mode; ++ struct grub_efi_pxe_mode *pxe_mode = NULL; ++ grub_uint8_t *packet_buf; ++ grub_size_t packet_bufsz ; ++ int ipv6; ++ struct grub_net_buff *nb = NULL; ++ + if (card->driver != &efidriver) + continue; ++ + cdp = grub_efi_get_device_path (card->efi_handle); + if (! cdp) + continue; ++ ++ ldp = grub_efi_find_last_device_path (dp); ++ + if (grub_efi_compare_device_paths (dp, cdp) != 0) + { +- grub_efi_device_path_t *ldp, *dup_dp, *dup_ldp; ++ grub_efi_device_path_t *dup_dp, *dup_ldp; + int match; + + /* EDK2 UEFI PXE driver creates pseudo devices with type IPv4/IPv6 +@@ -377,14 +790,33 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + devices. We skip them when enumerating cards, so here we need to + find matching MAC device. + */ +- ldp = grub_efi_find_last_device_path (dp); + if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE + || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE +- && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) + continue; + dup_dp = grub_efi_duplicate_device_path (dp); + if (!dup_dp) + continue; ++ ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) ++ { ++ dup_ldp = grub_efi_find_last_device_path (dup_dp); ++ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ dup_ldp->length = sizeof (*dup_ldp); ++ } ++ ++ dup_ldp = grub_efi_find_last_device_path (dup_dp); ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE) ++ { ++ dup_ldp = grub_efi_find_last_device_path (dup_dp); ++ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ dup_ldp->length = sizeof (*dup_ldp); ++ } ++ + dup_ldp = grub_efi_find_last_device_path (dup_dp); + dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; + dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; +@@ -394,46 +826,114 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + if (!match) + continue; + } ++ + pxe = grub_efi_open_protocol (hnd, &pxe_io_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); +- if (! pxe) +- continue; +- pxe_mode = pxe->mode; +- +- inter = grub_net_configure_by_dhcp_ack (card->name, card, 0, +- (struct grub_net_bootp_packet *) +- &pxe_mode->dhcp_ack, +- sizeof (pxe_mode->dhcp_ack), +- 1, device, path); +- +- if (inter != NULL) ++ if (!pxe) + { +- /* +- * Search the device path for any VLAN subtype and use it +- * to configure the interface. +- */ +- vlan_dp = dp; ++ nb = grub_efinet_create_dhcp_ack_from_device_path (dp, &ipv6); ++ if (!nb) ++ { ++ grub_print_error (); ++ continue; ++ } ++ packet_buf = nb->head; ++ packet_bufsz = nb->tail - nb->head; ++ } ++ else ++ { ++ pxe_mode = pxe->mode; ++ packet_buf = (grub_uint8_t *) &pxe_mode->dhcp_ack; ++ packet_bufsz = sizeof (pxe_mode->dhcp_ack); ++ ipv6 = pxe_mode->using_ipv6; ++ } + +- while (!GRUB_EFI_END_ENTIRE_DEVICE_PATH (vlan_dp)) ++ if (ipv6) ++ { ++ grub_dprintf ("efinet", "using ipv6 and dhcpv6\n"); ++ if (pxe_mode) ++ grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n", ++ pxe_mode->dhcp_ack_received ? "yes" : "no", ++ pxe_mode->dhcp_ack_received ? "" : " cannot continue"); ++ ++ inter = grub_net_configure_by_dhcpv6_reply (card->name, card, 0, ++ (struct grub_net_dhcp6_packet *) ++ packet_buf, ++ packet_bufsz, ++ 1, device, path); ++ if (grub_errno) ++ grub_print_error (); ++ if (inter && device && path) ++ grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); ++ if (grub_errno) ++ grub_print_error (); ++ } ++ else ++ { ++ grub_dprintf ("efinet", "using ipv4 and dhcp\n"); ++ ++ struct grub_net_bootp_packet *dhcp_ack = (struct grub_net_bootp_packet *) &pxe_mode->dhcp_ack; ++ ++ if (pxe_mode->proxy_offer_received) ++ { ++ grub_dprintf ("efinet", "proxy offer receive"); ++ struct grub_net_bootp_packet *proxy_offer = (struct grub_net_bootp_packet *) &pxe_mode->proxy_offer; ++ ++ if (proxy_offer && dhcp_ack->boot_file[0] == '\0') ++ { ++ grub_dprintf ("efinet", "setting values from proxy offer"); ++ /* Here we got a proxy offer and the dhcp_ack has a nil boot_file ++ * Copy the proxy DHCP offer details into the bootp_packet we are ++ * sending forward as they are the deatils we need. ++ */ ++ *dhcp_ack->server_name = *proxy_offer->server_name; ++ *dhcp_ack->boot_file = *proxy_offer->boot_file; ++ dhcp_ack->server_ip = proxy_offer->server_ip; ++ } ++ } ++ ++ inter = grub_net_configure_by_dhcp_ack (card->name, card, 0, ++ (struct grub_net_bootp_packet *) ++ packet_buf, ++ packet_bufsz, ++ 1, device, path); ++ grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); ++ if (inter != NULL) + { +- if (GRUB_EFI_DEVICE_PATH_TYPE (vlan_dp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE && +- GRUB_EFI_DEVICE_PATH_SUBTYPE (vlan_dp) == GRUB_EFI_VLAN_DEVICE_PATH_SUBTYPE) ++ /* ++ * Search the device path for any VLAN subtype and use it ++ * to configure the interface. ++ */ ++ vlan_dp = dp; ++ ++ while (!GRUB_EFI_END_ENTIRE_DEVICE_PATH (vlan_dp)) + { +- vlan = (grub_efi_vlan_device_path_t *) vlan_dp; +- inter->vlantag = vlan->vlan_id; +- break; ++ if (GRUB_EFI_DEVICE_PATH_TYPE (vlan_dp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE && ++ GRUB_EFI_DEVICE_PATH_SUBTYPE (vlan_dp) == GRUB_EFI_VLAN_DEVICE_PATH_SUBTYPE) ++ { ++ vlan = (grub_efi_vlan_device_path_t *) vlan_dp; ++ inter->vlantag = vlan->vlan_id; ++ break; ++ } ++ ++ vlan_dp_len = GRUB_EFI_DEVICE_PATH_LENGTH (vlan_dp); ++ vlan_dp = (grub_efi_device_path_t *) ((grub_efi_uint8_t *) vlan_dp + vlan_dp_len); + } +- +- vlan_dp_len = GRUB_EFI_DEVICE_PATH_LENGTH (vlan_dp); +- vlan_dp = (grub_efi_device_path_t *) ((grub_efi_uint8_t *) vlan_dp + vlan_dp_len); + } + } ++ ++ if (nb) ++ grub_netbuff_free (nb); ++ + return; + } + } + + GRUB_MOD_INIT(efinet) + { ++ if (grub_efi_net_config) ++ return; ++ + grub_efinet_findcards (); + grub_efi_net_config = grub_efi_net_config_real; + } +@@ -445,5 +945,7 @@ GRUB_MOD_FINI(efinet) + FOR_NET_CARDS_SAFE (card, next) + if (card->driver == &efidriver) + grub_net_card_unregister (card); ++ ++ grub_efi_net_config = NULL; + } + +diff --git a/grub-core/net/drivers/emu/emunet.c b/grub-core/net/drivers/emu/emunet.c +index 5f311d40f..7461d13bb 100644 +--- a/grub-core/net/drivers/emu/emunet.c ++++ b/grub-core/net/drivers/emu/emunet.c +@@ -46,6 +46,7 @@ static struct grub_net_card emucard = + .mtu = 1500, + .default_address = { + .type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET, ++ . len = 6, + {.mac = {0, 1, 2, 3, 4, 5}} + }, + .flags = 0 +diff --git a/grub-core/net/drivers/i386/pc/pxe.c b/grub-core/net/drivers/i386/pc/pxe.c +index db17186ee..816d1d0ee 100644 +--- a/grub-core/net/drivers/i386/pc/pxe.c ++++ b/grub-core/net/drivers/i386/pc/pxe.c +@@ -386,20 +386,21 @@ GRUB_MOD_INIT(pxe) + grub_memset (ui, 0, sizeof (*ui)); + grub_pxe_call (GRUB_PXENV_UNDI_GET_INFORMATION, ui, pxe_rm_entry); + ++ grub_pxe_card.default_address.len = 6; + grub_memcpy (grub_pxe_card.default_address.mac, ui->current_addr, +- sizeof (grub_pxe_card.default_address.mac)); +- for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++) ++ grub_pxe_card.default_address.len); ++ for (i = 0; i < grub_pxe_card.default_address.len; i++) + if (grub_pxe_card.default_address.mac[i] != 0) + break; +- if (i != sizeof (grub_pxe_card.default_address.mac)) ++ if (i != grub_pxe_card.default_address.len) + { +- for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++) ++ for (i = 0; i < grub_pxe_card.default_address.len; i++) + if (grub_pxe_card.default_address.mac[i] != 0xff) + break; + } +- if (i == sizeof (grub_pxe_card.default_address.mac)) ++ if (i == grub_pxe_card.default_address.len) + grub_memcpy (grub_pxe_card.default_address.mac, ui->permanent_addr, +- sizeof (grub_pxe_card.default_address.mac)); ++ grub_pxe_card.default_address.len); + grub_pxe_card.mtu = ui->mtu; + + grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c +index 78f03df8e..c56461ff1 100644 +--- a/grub-core/net/drivers/ieee1275/ofnet.c ++++ b/grub-core/net/drivers/ieee1275/ofnet.c +@@ -160,6 +160,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath, + grub_uint16_t vlantag = 0; + + hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ hw_addr.len = 6; + + args = bootpath + grub_strlen (devpath) + 1; + do +@@ -491,6 +492,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias) + grub_memcpy (&lla.mac, pprop, 6); + + lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ lla.len = 6; + card->default_address = lla; + + card->txbufsize = ALIGN_UP (card->mtu, 64) + 256; +diff --git a/grub-core/net/drivers/uboot/ubootnet.c b/grub-core/net/drivers/uboot/ubootnet.c +index b9d5a0cd4..9f3354a1b 100644 +--- a/grub-core/net/drivers/uboot/ubootnet.c ++++ b/grub-core/net/drivers/uboot/ubootnet.c +@@ -131,6 +131,7 @@ GRUB_MOD_INIT (ubootnet) + + grub_memcpy (&(card->default_address.mac), &devinfo->di_net.hwaddr, 6); + card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ card->default_address.len = 6; + + card->txbufsize = ALIGN_UP (card->mtu, 64) + 256; + card->txbuf = grub_zalloc (card->txbufsize); +diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c +new file mode 100644 +index 000000000..6cc0dad85 +--- /dev/null ++++ b/grub-core/net/efi/dhcp.c +@@ -0,0 +1,400 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef GRUB_EFI_NET_DEBUG ++static void ++dhcp4_mode_print (grub_efi_dhcp4_mode_data_t *mode) ++{ ++ switch (mode->state) ++ { ++ case GRUB_EFI_DHCP4_STOPPED: ++ grub_printf ("STATE: STOPPED\n"); ++ break; ++ case GRUB_EFI_DHCP4_INIT: ++ grub_printf ("STATE: INIT\n"); ++ break; ++ case GRUB_EFI_DHCP4_SELECTING: ++ grub_printf ("STATE: SELECTING\n"); ++ break; ++ case GRUB_EFI_DHCP4_REQUESTING: ++ grub_printf ("STATE: REQUESTING\n"); ++ break; ++ case GRUB_EFI_DHCP4_BOUND: ++ grub_printf ("STATE: BOUND\n"); ++ break; ++ case GRUB_EFI_DHCP4_RENEWING: ++ grub_printf ("STATE: RENEWING\n"); ++ break; ++ case GRUB_EFI_DHCP4_REBINDING: ++ grub_printf ("STATE: REBINDING\n"); ++ break; ++ case GRUB_EFI_DHCP4_INIT_REBOOT: ++ grub_printf ("STATE: INIT_REBOOT\n"); ++ break; ++ case GRUB_EFI_DHCP4_REBOOTING: ++ grub_printf ("STATE: REBOOTING\n"); ++ break; ++ default: ++ grub_printf ("STATE: UNKNOWN\n"); ++ break; ++ } ++ ++ grub_printf ("CLIENT_ADDRESS: %u.%u.%u.%u\n", ++ mode->client_address[0], ++ mode->client_address[1], ++ mode->client_address[2], ++ mode->client_address[3]); ++ grub_printf ("SERVER_ADDRESS: %u.%u.%u.%u\n", ++ mode->server_address[0], ++ mode->server_address[1], ++ mode->server_address[2], ++ mode->server_address[3]); ++ grub_printf ("SUBNET_MASK: %u.%u.%u.%u\n", ++ mode->subnet_mask[0], ++ mode->subnet_mask[1], ++ mode->subnet_mask[2], ++ mode->subnet_mask[3]); ++ grub_printf ("ROUTER_ADDRESS: %u.%u.%u.%u\n", ++ mode->router_address[0], ++ mode->router_address[1], ++ mode->router_address[2], ++ mode->router_address[3]); ++} ++#endif ++ ++static grub_efi_ipv4_address_t * ++grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packet_t *reply_packet) ++{ ++ grub_efi_dhcp4_packet_option_t **option_list; ++ grub_efi_status_t status; ++ grub_efi_uint32_t option_count = 0; ++ grub_efi_uint32_t i; ++ ++ status = dhcp4->parse(dhcp4, reply_packet, &option_count, NULL); ++ ++ if (status != GRUB_EFI_BUFFER_TOO_SMALL) ++ return NULL; ++ ++ option_list = grub_calloc (option_count, sizeof(*option_list)); ++ if (!option_list) ++ return NULL; ++ ++ status = dhcp4->parse(dhcp4, reply_packet, &option_count, option_list); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (option_list); ++ return NULL; ++ } ++ ++ for (i = 0; i < option_count; ++i) ++ { ++ if (option_list[i]->op_code == 6) ++ { ++ grub_efi_ipv4_address_t *dns_address; ++ ++ if (((option_list[i]->length & 0x3) != 0) || (option_list[i]->length == 0)) ++ continue; ++ ++ /* We only contact primary dns */ ++ dns_address = grub_malloc (sizeof (*dns_address)); ++ if (!dns_address) ++ { ++ grub_free (option_list); ++ return NULL; ++ } ++ grub_memcpy (dns_address, option_list[i]->data, sizeof (dns_address)); ++ grub_free (option_list); ++ return dns_address; ++ } ++ } ++ ++ grub_free (option_list); ++ return NULL; ++} ++ ++#if 0 ++/* Somehow this doesn't work ... */ ++static grub_err_t ++grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_pxe_t *pxe = dev->ip4_pxe; ++ grub_efi_pxe_mode_t *mode = pxe->mode; ++ grub_efi_status_t status; ++ ++ if (!mode->started) ++ { ++ status = pxe->start(pxe, 0); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't start PXE\n"); ++ } ++ ++ status = pxe->dhcp(pxe, 0); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 configure failed, %d\n", (int)status); ++ continue; ++ } ++ ++ dev->prefer_ip6 = 0; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++#endif ++ ++static grub_err_t ++grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, ++ char **args) ++{ ++ struct grub_efi_net_device *netdev; ++ ++ for (netdev = net_devices; netdev; netdev = netdev->next) ++ { ++ grub_efi_status_t status; ++ grub_efi_dhcp4_mode_data_t mode; ++ grub_efi_dhcp4_config_data_t config; ++ grub_efi_dhcp4_packet_option_t *options; ++ grub_efi_ipv4_address_t *dns_address; ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_net_ip_address_t ip_addr; ++ grub_efi_net_interface_t *inf = NULL; ++ ++ if (argc > 0 && grub_strcmp (netdev->card_name, args[0]) != 0) ++ continue; ++ ++ grub_memset (&config, 0, sizeof(config)); ++ ++ config.option_count = 1; ++ options = grub_malloc (sizeof(*options) + 2); ++ /* Parameter request list */ ++ options->op_code = 55; ++ options->length = 3; ++ /* subnet mask */ ++ options->data[0] = 1; ++ /* router */ ++ options->data[1] = 3; ++ /* DNS */ ++ options->data[2] = 6; ++ config.option_list = &options; ++ ++ /* FIXME: What if the dhcp has bounded */ ++ status = netdev->dhcp4->configure(netdev->dhcp4, &config); ++ grub_free (options); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 configure failed, %d\n", (int)status); ++ continue; ++ } ++ ++ status = netdev->dhcp4->start(netdev->dhcp4, NULL); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 start failed, %d\n", (int)status); ++ continue; ++ } ++ ++ status = netdev->dhcp4->get_mode_data(netdev->dhcp4, &mode); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 get mode failed, %d\n", (int)status); ++ continue; ++ } ++ ++#ifdef GRUB_EFI_NET_DEBUG ++ dhcp4_mode_print (&mode); ++#endif ++ ++ for (inf = netdev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6 == 0) ++ break; ++ ++ grub_memcpy (net_ip.ip4.address, mode.client_address, sizeof (net_ip.ip4.address)); ++ grub_memcpy (net_ip.ip4.subnet_mask, mode.subnet_mask, sizeof (net_ip.ip4.subnet_mask)); ++ ++ if (!inf) ++ { ++ char *name = grub_xasprintf ("%s:dhcp", netdev->card_name); ++ ++ net_ip.is_ip6 = 0; ++ inf = grub_efi_net_create_interface (netdev, ++ name, ++ &net_ip, ++ 1); ++ grub_free (name); ++ } ++ else ++ { ++ efi_net_interface_set_address (inf, &net_ip, 1); ++ } ++ ++ grub_memcpy (ip_addr.ip4, mode.router_address, sizeof (ip_addr.ip4)); ++ efi_net_interface_set_gateway (inf, &ip_addr); ++ ++ dns_address = grub_efi_dhcp4_parse_dns (netdev->dhcp4, mode.reply_packet); ++ if (dns_address) ++ efi_net_interface_set_dns (inf, (grub_efi_net_ip_address_t *)&dns_address); ++ ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++ ++static grub_err_t ++grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, ++ char **args) ++{ ++ struct grub_efi_net_device *dev; ++ grub_efi_uint32_t ia_id; ++ ++ for (dev = net_devices, ia_id = 0; dev; dev = dev->next, ia_id++) ++ { ++ grub_efi_dhcp6_config_data_t config; ++ grub_efi_dhcp6_packet_option_t *option_list[1]; ++ grub_efi_dhcp6_packet_option_t *opt; ++ grub_efi_status_t status; ++ grub_efi_dhcp6_mode_data_t mode; ++ grub_efi_dhcp6_retransmission_t retrans; ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; ++ grub_efi_net_interface_t *inf = NULL; ++ ++ if (argc > 0 && grub_strcmp (dev->card_name, args[0]) != 0) ++ continue; ++ ++ opt = grub_malloc (sizeof(*opt) + 2 * sizeof (grub_efi_uint16_t)); ++ ++#define GRUB_EFI_DHCP6_OPT_ORO 6 ++ ++ opt->op_code = grub_cpu_to_be16_compile_time (GRUB_EFI_DHCP6_OPT_ORO); ++ opt->op_len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_efi_uint16_t)); ++ ++#define GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL 59 ++#define GRUB_EFI_DHCP6_OPT_DNS_SERVERS 23 ++ ++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL)); ++ grub_set_unaligned16 (opt->data + 1 * sizeof (grub_efi_uint16_t), ++ grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS)); ++ ++ option_list[0] = opt; ++ retrans.irt = 4; ++ retrans.mrc = 4; ++ retrans.mrt = 32; ++ retrans.mrd = 60; ++ ++ config.dhcp6_callback = NULL; ++ config.callback_context = NULL; ++ config.option_count = 1; ++ config.option_list = option_list; ++ config.ia_descriptor.ia_id = ia_id; ++ config.ia_descriptor.type = GRUB_EFI_DHCP6_IA_TYPE_NA; ++ config.ia_info_event = NULL; ++ config.reconfigure_accept = 0; ++ config.rapid_commit = 0; ++ config.solicit_retransmission = &retrans; ++ ++ status = dev->dhcp6->configure(dev->dhcp6, &config); ++ grub_free (opt); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp6 configure failed, %d\n", (int)status); ++ continue; ++ } ++ status = dev->dhcp6->start(dev->dhcp6); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp6 start failed, %d\n", (int)status); ++ continue; ++ } ++ ++ status = dev->dhcp6->get_mode_data(dev->dhcp6, &mode, NULL); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 get mode failed, %d\n", (int)status); ++ continue; ++ } ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6 == 1) ++ break; ++ ++ grub_memcpy (net_ip.ip6.address, mode.ia->ia_address[0].ip_address, sizeof (net_ip.ip6.address)); ++ net_ip.ip6.prefix_length = 64; ++ net_ip.ip6.is_anycast = 0; ++ net_ip.is_ip6 = 1; ++ ++ if (!inf) ++ { ++ char *name = grub_xasprintf ("%s:dhcp", dev->card_name); ++ ++ inf = grub_efi_net_create_interface (dev, ++ name, ++ &net_ip, ++ 1); ++ grub_free (name); ++ } ++ else ++ { ++ efi_net_interface_set_address (inf, &net_ip, 1); ++ } ++ ++ { ++ grub_efi_uint32_t count = 0; ++ grub_efi_dhcp6_packet_option_t **options = NULL; ++ grub_efi_uint32_t i; ++ ++ status = dev->dhcp6->parse(dev->dhcp6, mode.ia->reply_packet, &count, NULL); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL && count) ++ { ++ options = grub_calloc (count, sizeof(*options)); ++ if (options) ++ status = dev->dhcp6->parse(dev->dhcp6, mode.ia->reply_packet, &count, options); ++ else ++ status = GRUB_EFI_OUT_OF_RESOURCES; ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ if (options) ++ grub_free (options); ++ continue; ++ } ++ ++ for (i = 0; i < count; ++i) ++ { ++ if (options[i]->op_code == grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS)) ++ { ++ grub_efi_net_ip_address_t dns; ++ grub_memcpy (dns.ip6, options[i]->data, sizeof(net_ip.ip6)); ++ efi_net_interface_set_dns (inf, &dns); ++ break; ++ } ++ } ++ ++ if (options) ++ grub_free (options); ++ } ++ ++ b->free_pool(mode.client_id); ++ b->free_pool(mode.ia); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_command_func_t grub_efi_net_bootp = grub_cmd_efi_bootp; ++grub_command_func_t grub_efi_net_bootp6 = grub_cmd_efi_bootp6; +diff --git a/grub-core/net/efi/efi_netfs.c b/grub-core/net/efi/efi_netfs.c +new file mode 100644 +index 000000000..ef371d885 +--- /dev/null ++++ b/grub-core/net/efi/efi_netfs.c +@@ -0,0 +1,57 @@ ++#include ++#include ++#define EFI_NET_CMD_PREFIX "net_efi" ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_command_t cmd_efi_lsroutes; ++static grub_command_t cmd_efi_lscards; ++static grub_command_t cmd_efi_lsaddrs; ++static grub_command_t cmd_efi_addaddr; ++static grub_command_t cmd_efi_bootp; ++static grub_command_t cmd_efi_bootp6; ++ ++static int initialized; ++ ++GRUB_MOD_INIT(efi_netfs) ++{ ++ if (grub_net_open) ++ return; ++ ++ if (grub_efi_net_fs_init ()) ++ { ++ cmd_efi_lsroutes = grub_register_command ("net_efi_ls_routes", grub_efi_net_list_routes, ++ "", N_("list network routes")); ++ cmd_efi_lscards = grub_register_command ("net_efi_ls_cards", grub_efi_net_list_cards, ++ "", N_("list network cards")); ++ cmd_efi_lsaddrs = grub_register_command ("net_efi_ls_addr", grub_efi_net_list_addrs, ++ "", N_("list network addresses")); ++ cmd_efi_addaddr = grub_register_command ("net_efi_add_addr", grub_efi_net_add_addr, ++ N_("SHORTNAME CARD ADDRESS [HWADDRESS]"), ++ N_("Add a network address.")); ++ cmd_efi_bootp = grub_register_command ("net_efi_bootp", grub_efi_net_bootp, ++ N_("[CARD]"), ++ N_("perform a bootp autoconfiguration")); ++ cmd_efi_bootp6 = grub_register_command ("net_efi_bootp6", grub_efi_net_bootp6, ++ N_("[CARD]"), ++ N_("perform a bootp autoconfiguration")); ++ initialized = 1; ++ } ++} ++ ++GRUB_MOD_FINI(efi_netfs) ++{ ++ if (initialized) ++ { ++ grub_unregister_command (cmd_efi_lsroutes); ++ grub_unregister_command (cmd_efi_lscards); ++ grub_unregister_command (cmd_efi_lsaddrs); ++ grub_unregister_command (cmd_efi_addaddr); ++ grub_unregister_command (cmd_efi_bootp); ++ grub_unregister_command (cmd_efi_bootp6); ++ grub_efi_net_fs_fini (); ++ initialized = 0; ++ return; ++ } ++} +diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c +new file mode 100644 +index 000000000..5bdb47548 +--- /dev/null ++++ b/grub-core/net/efi/http.c +@@ -0,0 +1,494 @@ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++http_configure (struct grub_efi_net_device *dev, int prefer_ip6) ++{ ++ grub_efi_ipv6_address_t address; ++ grub_efi_http_config_data_t http_config; ++ grub_efi_httpv4_access_point_t httpv4_node; ++ grub_efi_httpv6_access_point_t httpv6_node; ++ grub_efi_status_t status; ++ int https; ++ char *http_url; ++ const char *rest, *http_server, *http_path = NULL; ++ ++ http_server = grub_env_get ("root"); ++ https = (grub_strncmp (http_server, "https", 5) == 0) ? 1 : 0; ++ ++ /* extract http server + port */ ++ if (http_server) ++ { ++ http_server = grub_strchr (http_server, ','); ++ if (http_server) ++ http_server++; ++ } ++ ++ /* fw_path is like (http,192.168.1.1:8000)/httpboot, extract path part */ ++ http_path = grub_env_get ("fw_path"); ++ if (http_path) ++ { ++ http_path = grub_strchr (http_path, ')'); ++ if (http_path) ++ { ++ http_path++; ++ grub_env_unset ("http_path"); ++ grub_env_set ("http_path", http_path); ++ grub_env_export ("http_path"); ++ } ++ } ++ ++ if (http_server && http_path) ++ { ++ if (grub_efi_string_to_ip6_address (http_server, &address, &rest) && *rest == 0) ++ http_url = grub_xasprintf ("%s://[%s]%s", https ? "https" : "http", http_server, http_path); ++ else ++ http_url = grub_xasprintf ("%s://%s%s", https ? "https" : "http", http_server, http_path); ++ if (http_url) ++ { ++ grub_env_unset ("http_url"); ++ grub_env_set ("http_url", http_url); ++ grub_free (http_url); ++ } ++ } ++ ++ grub_efi_http_t *http = dev->http; ++ ++ grub_memset (&http_config, 0, sizeof(http_config)); ++ http_config.http_version = GRUB_EFI_HTTPVERSION11; ++ http_config.timeout_millisec = 5000; ++ ++ if (prefer_ip6) ++ { ++ grub_efi_uintn_t sz; ++ grub_efi_ip6_config_manual_address_t manual_address; ++ ++ http_config.local_address_is_ipv6 = 1; ++ sz = sizeof (manual_address); ++ status = dev->ip6_config->get_data(dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, &manual_address); ++ ++ if (status == GRUB_EFI_NOT_FOUND) ++ { ++ grub_printf ("The MANUAL ADDRESS is not found\n"); ++ } ++ ++ /* FIXME: The manual interface would return BUFFER TOO SMALL !!! */ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("??? %d\n",(int) status); ++ return; ++ } ++ ++ grub_memcpy (httpv6_node.local_address, manual_address.address, sizeof (httpv6_node.local_address)); ++ httpv6_node.local_port = 0; ++ http_config.access_point.ipv6_node = &httpv6_node; ++ } ++ else ++ { ++ http_config.local_address_is_ipv6 = 0; ++ grub_memset (&httpv4_node, 0, sizeof(httpv4_node)); ++ httpv4_node.use_default_address = 1; ++ ++ /* Use random port here */ ++ /* See TcpBind() in edk2/NetworkPkg/TcpDxe/TcpDispatcher.c */ ++ httpv4_node.local_port = 0; ++ http_config.access_point.ipv4_node = &httpv4_node; ++ } ++ ++ status = http->configure(http, &http_config); ++ ++ if (status == GRUB_EFI_ALREADY_STARTED) ++ { ++ /* XXX: This hangs HTTPS boot */ ++#if 0 ++ if (http->configure(http, NULL) != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_IO, N_("couldn't reset http instance")); ++ grub_print_error (); ++ return; ++ } ++ status = http->configure(http, &http_config); ++#endif ++ return; ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_IO, N_("couldn't configure http protocol, reason: %d"), (int)status); ++ grub_print_error (); ++ return ; ++ } ++} ++ ++static grub_efi_boolean_t request_callback_done; ++static grub_efi_boolean_t response_callback_done; ++ ++static void ++__grub_efi_api grub_efi_http_request_callback (grub_efi_event_t event __attribute__ ((unused)), ++ void *context __attribute__ ((unused))) ++{ ++ request_callback_done = 1; ++} ++ ++static void ++__grub_efi_api grub_efi_http_response_callback (grub_efi_event_t event __attribute__ ((unused)), ++ void *context __attribute__ ((unused))) ++{ ++ response_callback_done = 1; ++} ++ ++static grub_err_t ++efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, int headeronly, grub_off_t *file_size) ++{ ++ grub_efi_http_request_data_t request_data; ++ grub_efi_http_message_t request_message; ++ grub_efi_http_token_t request_token; ++ grub_efi_http_response_data_t response_data; ++ grub_efi_http_message_t response_message; ++ grub_efi_http_token_t response_token; ++ grub_efi_http_header_t request_headers[3]; ++ ++ grub_efi_status_t status; ++ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; ++ char *url = NULL; ++ char *hostname = NULL; ++ ++ { ++ grub_efi_ipv6_address_t address; ++ const char *rest; ++ grub_efi_char16_t *ucs2_url; ++ grub_size_t url_len, ucs2_url_len; ++ const char *protocol = (use_https == 1) ? "https" : "http"; ++ ++ if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0) ++ { ++ hostname = grub_xasprintf ("[%s]", server); ++ if (!hostname) ++ return GRUB_ERR_OUT_OF_MEMORY; ++ ++ server = hostname; ++ ++ url = grub_xasprintf ("%s://%s%s", protocol, server, name); ++ if (!url) ++ { ++ grub_free (hostname); ++ return GRUB_ERR_OUT_OF_MEMORY; ++ } ++ } ++ else ++ { ++ url = grub_xasprintf ("%s://%s%s", protocol, server, name); ++ } ++ ++ if (!url) ++ { ++ return grub_errno; ++ } ++ ++ url_len = grub_strlen (url); ++ ucs2_url_len = url_len * GRUB_MAX_UTF16_PER_UTF8; ++ ucs2_url = grub_malloc ((ucs2_url_len + 1) * sizeof (ucs2_url[0])); ++ ++ if (!ucs2_url) ++ { ++ grub_free (url); ++ return grub_errno; ++ } ++ ++ ucs2_url_len = grub_utf8_to_utf16 (ucs2_url, ucs2_url_len, (grub_uint8_t *)url, url_len, NULL); /* convert string format from ascii to usc2 */ ++ ucs2_url[ucs2_url_len] = 0; ++ grub_free (url); ++ request_data.url = ucs2_url; ++ } ++ ++ request_headers[0].field_name = (grub_efi_char8_t *)"Host"; ++ request_headers[0].field_value = (grub_efi_char8_t *)server; ++ request_headers[1].field_name = (grub_efi_char8_t *)"Accept"; ++ request_headers[1].field_value = (grub_efi_char8_t *)"*/*"; ++ request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent"; ++ request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0"; ++ ++ request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET; ++ ++ request_message.data.request = &request_data; ++ request_message.header_count = 3; ++ request_message.headers = request_headers; ++ request_message.body_length = 0; ++ request_message.body = NULL; ++ ++ /* request token */ ++ request_token.event = NULL; ++ request_token.status = GRUB_EFI_NOT_READY; ++ request_token.message = &request_message; ++ ++ request_callback_done = 0; ++ status = b->create_event(GRUB_EFI_EVT_NOTIFY_SIGNAL, GRUB_EFI_TPL_CALLBACK, ++ grub_efi_http_request_callback, NULL, ++ &request_token.event); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", (unsigned) status); ++ } ++ ++ status = http->request(http, &request_token); ++ ++ if (hostname) ++ grub_free (hostname); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ b->close_event(request_token.event); ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to send a request! status=0x%x\n", (unsigned) status); ++ } ++ /* TODO: Add Timeout */ ++ while (!request_callback_done) ++ http->poll(http); ++ ++ response_data.status_code = GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS; ++ response_message.data.response = &response_data; ++ /* herader_count will be updated by the HTTP driver on response */ ++ response_message.header_count = 0; ++ /* headers will be populated by the driver on response */ ++ response_message.headers = NULL; ++ /* use zero BodyLength to only receive the response headers */ ++ response_message.body_length = 0; ++ response_message.body = NULL; ++ response_token.event = NULL; ++ ++ status = b->create_event(GRUB_EFI_EVT_NOTIFY_SIGNAL, GRUB_EFI_TPL_CALLBACK, ++ grub_efi_http_response_callback, NULL, ++ &response_token.event); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ b->close_event(request_token.event); ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", (unsigned) status); ++ } ++ ++ response_token.status = GRUB_EFI_SUCCESS; ++ response_token.message = &response_message; ++ ++ /* wait for HTTP response */ ++ response_callback_done = 0; ++ status = http->response(http, &response_token); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ b->close_event(response_token.event); ++ b->close_event(request_token.event); ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to receive a response! status=%d\n", (int)status); ++ } ++ ++ /* TODO: Add Timeout */ ++ while (!response_callback_done) ++ http->poll(http); ++ ++ if (response_message.data.response->status_code != GRUB_EFI_HTTP_STATUS_200_OK) ++ { ++ grub_efi_http_status_code_t status_code = response_message.data.response->status_code; ++ ++ if (response_message.headers) ++ b->free_pool(response_message.headers); ++ b->close_event(response_token.event); ++ b->close_event(request_token.event); ++ grub_free (request_data.url); ++ if (status_code == GRUB_EFI_HTTP_STATUS_404_NOT_FOUND) ++ { ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, _("file `%s' not found"), name); ++ } ++ else ++ { ++ return grub_error (GRUB_ERR_NET_UNKNOWN_ERROR, ++ _("unsupported uefi http status code 0x%x"), status_code); ++ } ++ } ++ ++ if (file_size) ++ { ++ int i; ++ /* parse the length of the file from the ContentLength header */ ++ for (*file_size = 0, i = 0; i < (int)response_message.header_count; ++i) ++ { ++ if (!grub_strcmp((const char*)response_message.headers[i].field_name, "Content-Length")) ++ { ++ *file_size = grub_strtoul((const char*)response_message.headers[i].field_value, 0, 10); ++ break; ++ } ++ } ++ } ++ ++ if (response_message.headers) ++ b->free_pool(response_message.headers); ++ b->close_event(response_token.event); ++ b->close_event(request_token.event); ++ grub_free (request_data.url); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++efihttp_read (struct grub_efi_net_device *dev, ++ char *buf, ++ grub_size_t len) ++{ ++ grub_efi_http_message_t response_message; ++ grub_efi_http_token_t response_token; ++ ++ grub_efi_status_t status; ++ grub_size_t sum = 0; ++ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; ++ grub_efi_http_t *http = dev->http; ++ ++ if (!len) ++ { ++ grub_error (GRUB_ERR_BUG, "Invalid arguments to EFI HTTP Read"); ++ return -1; ++ } ++ ++ b->create_event(GRUB_EFI_EVT_NOTIFY_SIGNAL, GRUB_EFI_TPL_CALLBACK, ++ grub_efi_http_response_callback, NULL, ++ &response_token.event); ++ ++ while (len) ++ { ++ response_message.data.response = NULL; ++ response_message.header_count = 0; ++ response_message.headers = NULL; ++ response_message.body_length = len; ++ response_message.body = buf; ++ ++ response_token.message = &response_message; ++ response_token.status = GRUB_EFI_NOT_READY; ++ ++ response_callback_done = 0; ++ ++ status = http->response(http, &response_token); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ b->close_event(response_token.event); ++ grub_error (GRUB_ERR_IO, "Error! status=%d\n", (int)status); ++ return -1; ++ } ++ ++ while (!response_callback_done) ++ http->poll(http); ++ ++ sum += response_message.body_length; ++ buf += response_message.body_length; ++ len -= response_message.body_length; ++ } ++ ++ b->close_event(response_token.event); ++ ++ return sum; ++} ++ ++static grub_err_t ++grub_efihttp_open (struct grub_efi_net_device *dev, ++ int prefer_ip6 __attribute__ ((unused)), ++ grub_file_t file, ++ const char *filename __attribute__ ((unused)), ++ int type) ++{ ++ grub_err_t err; ++ grub_off_t size = 0; ++ char *buf = NULL; ++ char *file_name = NULL; ++ const char *http_path; ++ ++ /* If path is relative, prepend http_path */ ++ http_path = grub_env_get ("http_path"); ++ if (http_path && file->device->net->name[0] != '/') { ++ file_name = grub_xasprintf ("%s/%s", http_path, file->device->net->name); ++ if (!file_name) ++ return grub_errno; ++ } ++ ++ err = efihttp_request (dev->http, file->device->net->server, ++ file_name ? file_name : file->device->net->name, type, 1, 0); ++ if (err != GRUB_ERR_NONE) ++ { ++ grub_free (file_name); ++ return err; ++ } ++ ++ err = efihttp_request (dev->http, file->device->net->server, ++ file_name ? file_name : file->device->net->name, type, 0, &size); ++ grub_free (file_name); ++ if (err != GRUB_ERR_NONE) ++ { ++ return err; ++ } ++ ++ if (size) ++ { ++ buf = grub_malloc (size); ++ efihttp_read (dev, buf, size); ++ } ++ ++ file->size = size; ++ file->data = buf; ++ file->not_easily_seekable = 0; ++ file->device->net->offset = 0; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_efihttp_close (struct grub_efi_net_device *dev __attribute__ ((unused)), ++ int prefer_ip6 __attribute__ ((unused)), ++ grub_file_t file) ++{ ++ if (file->data) ++ grub_free (file->data); ++ ++ file->data = 0; ++ file->offset = 0; ++ file->size = 0; ++ file->device->net->offset = 0; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++grub_efihttp_read (struct grub_efi_net_device *dev __attribute__((unused)), ++ int prefer_ip6 __attribute__((unused)), ++ grub_file_t file, ++ char *buf, ++ grub_size_t len) ++{ ++ grub_size_t r = len; ++ ++ if (!file->data || !buf || !len) ++ return 0; ++ ++ if ((file->device->net->offset + len) > file->size) ++ r = file->size - file->device->net->offset; ++ ++ if (r) ++ { ++ grub_memcpy (buf, (char *)file->data + file->device->net->offset, r); ++ file->device->net->offset += r; ++ } ++ ++ return r; ++} ++ ++struct grub_efi_net_io io_http = ++ { ++ .configure = http_configure, ++ .open = grub_efihttp_open, ++ .read = grub_efihttp_read, ++ .close = grub_efihttp_close ++ }; +diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c +new file mode 100644 +index 000000000..85a090ec4 +--- /dev/null ++++ b/grub-core/net/efi/ip4_config.c +@@ -0,0 +1,421 @@ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++char * ++grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address) ++{ ++ char *hw_addr, *p; ++ grub_size_t sz, s, i; ++ ++ if (grub_mul (hw_address_size, sizeof ("XX:") - 1, &sz) || ++ grub_add (sz, 1, &sz)) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ return NULL; ++ } ++ ++ hw_addr = grub_malloc (sz); ++ if (!hw_addr) ++ return NULL; ++ ++ p = hw_addr; ++ s = sz; ++ for (i = 0; i < hw_address_size; i++) ++ { ++ grub_snprintf (p, sz, "%02x:", hw_address[i]); ++ p += sizeof ("XX:") - 1; ++ s -= sizeof ("XX:") - 1; ++ } ++ ++ hw_addr[sz - 2] = '\0'; ++ return hw_addr; ++} ++ ++char * ++grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address) ++{ ++ char *addr; ++ ++ addr = grub_malloc (sizeof ("XXX.XXX.XXX.XXX")); ++ if (!addr) ++ return NULL; ++ ++ /* FIXME: Use grub_xasprintf ? */ ++ grub_snprintf (addr, ++ sizeof ("XXX.XXX.XXX.XXX"), ++ "%u.%u.%u.%u", ++ (*address)[0], ++ (*address)[1], ++ (*address)[2], ++ (*address)[3]); ++ ++ return addr; ++} ++ ++int ++grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest) ++{ ++ grub_uint32_t newip = 0; ++ grub_size_t i; ++ int ncolon = 0; ++ const char *ptr = val; ++ ++ /* Check that is not an IPv6 address */ ++ for (i = 0; i < grub_strlen(ptr); i++) ++ { ++ if (ptr[i] == '[' && i == 0) ++ return 0; ++ ++ if (ptr[i] == ':') ++ if (i == 0 || ++ncolon == 2) ++ return 0; ++ } ++ ++ for (i = 0; i < 4; i++) ++ { ++ unsigned long t; ++ t = grub_strtoul (ptr, &ptr, 0); ++ if (grub_errno) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ if (*ptr != '.' && i == 0) ++ { ++ /* XXX: t is in host byte order */ ++ newip = t; ++ break; ++ } ++ if (t & ~0xff) ++ return 0; ++ newip <<= 8; ++ newip |= t; ++ if (i != 3 && *ptr != '.') ++ return 0; ++ ptr++; ++ } ++ ++ newip = grub_cpu_to_be32 (newip); ++ ++ grub_memcpy (address, &newip, sizeof(*address)); ++ ++ if (rest) ++ *rest = (ptr - 1); ++ return 1; ++} ++ ++static grub_efi_ip4_config2_interface_info_t * ++efi_ip4_config_interface_info (grub_efi_ip4_config2_protocol_t *ip4_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ ++ sz = sizeof (*interface_info) + sizeof (*interface_info->route_table); ++ interface_info = grub_malloc (sz); ++ if (!interface_info) ++ return NULL; ++ ++ status = ip4_config->get_data(ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (interface_info); ++ interface_info = grub_malloc (sz); ++ status = ip4_config->get_data(ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ return interface_info; ++} ++ ++static grub_efi_ip4_config2_manual_address_t * ++efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = ip4_config->get_data(ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++char * ++grub_efi_ip4_interface_name (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ char *name; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE ++ * GRUB_MAX_UTF8_PER_UTF16 + 1); ++ *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name, ++ GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0; ++ grub_free (interface_info); ++ return name; ++} ++ ++static char * ++grub_efi_ip4_interface_hw_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ char *hw_addr; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address); ++ grub_free (interface_info); ++ ++ return hw_addr; ++} ++ ++static char * ++grub_efi_ip4_interface_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ char *addr; ++ ++ manual_address = efi_ip4_config_manual_address (dev->ip4_config); ++ ++ if (!manual_address) ++ return NULL; ++ ++ addr = grub_efi_ip4_address_to_string (&manual_address->address); ++ grub_free (manual_address); ++ return addr; ++} ++ ++ ++static int ++address_mask_size (grub_efi_ipv4_address_t *address) ++{ ++ grub_uint8_t i; ++ grub_uint32_t u32_addr = grub_be_to_cpu32 (grub_get_unaligned32 (address)); ++ ++ if (u32_addr == 0) ++ return 0; ++ ++ for (i = 0; i < 32 ; ++i) ++ { ++ if (u32_addr == ((0xffffffff >> i) << i)) ++ return (32 - i); ++ } ++ ++ return -1; ++} ++ ++static char ** ++grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ char **ret; ++ int id; ++ grub_size_t i, nmemb; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ if (!interface_info) ++ return NULL; ++ ++ if (grub_add (interface_info->route_table_size, 1, &nmemb)) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ return NULL; ++ } ++ ++ ret = grub_calloc (nmemb, sizeof (*ret)); ++ if (!ret) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ id = 0; ++ for (i = 0; i < interface_info->route_table_size; i++) ++ { ++ char *subnet, *gateway, *mask; ++ grub_uint32_t u32_subnet, u32_gateway; ++ int mask_size; ++ grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i; ++ grub_efi_net_interface_t *inf; ++ char *interface_name = NULL; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (!inf->prefer_ip6) ++ interface_name = inf->name; ++ ++ u32_gateway = grub_get_unaligned32 (&route_table->gateway_address); ++ gateway = grub_efi_ip4_address_to_string (&route_table->gateway_address); ++ u32_subnet = grub_get_unaligned32 (&route_table->subnet_address); ++ subnet = grub_efi_ip4_address_to_string (&route_table->subnet_address); ++ mask_size = address_mask_size (&route_table->subnet_mask); ++ mask = grub_efi_ip4_address_to_string (&route_table->subnet_mask); ++ if (u32_subnet && !u32_gateway && interface_name) ++ ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, subnet, mask_size, interface_name); ++ else if (u32_subnet && u32_gateway) ++ ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); ++ else if (!u32_subnet && u32_gateway) ++ ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); ++ grub_free (subnet); ++ grub_free (gateway); ++ grub_free (mask); ++ } ++ ++ ret[id] = NULL; ++ grub_free (interface_info); ++ return ret; ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_ip4_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ grub_efi_net_interface_t *inf; ++ int i; ++ grub_efi_ipv4_address_t *address = &ip_address->ip4; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ if (!interface_info) ++ return NULL; ++ ++ for (i = 0; i < (int)interface_info->route_table_size; i++) ++ { ++ grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i; ++ grub_uint32_t u32_address, u32_mask, u32_subnet; ++ ++ u32_address = grub_get_unaligned32 (address); ++ u32_subnet = grub_get_unaligned32 (route_table->subnet_address); ++ u32_mask = grub_get_unaligned32 (route_table->subnet_mask); ++ ++ /* SKIP Default GATEWAY */ ++ if (!u32_subnet && !u32_mask) ++ continue; ++ ++ if ((u32_address & u32_mask) == u32_subnet) ++ { ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (!inf->prefer_ip6) ++ { ++ grub_free (interface_info); ++ return inf; ++ } ++ } ++ } ++ ++ grub_free (interface_info); ++ return NULL; ++} ++ ++static int ++grub_efi_ip4_interface_set_manual_address (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int with_subnet) ++{ ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_manual_address_t *address = &net_ip->ip4; ++ ++ if (!with_subnet) ++ { ++ grub_efi_ip4_config2_manual_address_t *manual_address = ++ efi_ip4_config_manual_address (dev->ip4_config); ++ ++ if (manual_address) ++ { ++ grub_memcpy (address->subnet_mask, manual_address->subnet_mask, sizeof(address->subnet_mask)); ++ grub_free (manual_address); ++ } ++ else ++ { ++ /* XXX: */ ++ address->subnet_mask[0] = 0xff; ++ address->subnet_mask[1] = 0xff; ++ address->subnet_mask[2] = 0xff; ++ address->subnet_mask[3] = 0; ++ } ++ } ++ ++ status = dev->ip4_config->set_data(dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ sizeof(*address), address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ return 1; ++} ++ ++static int ++grub_efi_ip4_interface_set_gateway (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ grub_efi_status_t status; ++ ++ status = dev->ip4_config->set_data(dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY, ++ sizeof (address->ip4), &address->ip4); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++/* FIXME: Multiple DNS */ ++static int ++grub_efi_ip4_interface_set_dns (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ grub_efi_status_t status; ++ ++ status = dev->ip4_config->set_data(dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ sizeof (address->ip4), &address->ip4); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++grub_efi_net_ip_config_t *efi_net_ip4_config = &(grub_efi_net_ip_config_t) ++ { ++ .get_hw_address = grub_efi_ip4_interface_hw_address, ++ .get_address = grub_efi_ip4_interface_address, ++ .get_route_table = grub_efi_ip4_interface_route_table, ++ .best_interface = grub_efi_ip4_interface_match, ++ .set_address = grub_efi_ip4_interface_set_manual_address, ++ .set_gateway = grub_efi_ip4_interface_set_gateway, ++ .set_dns = grub_efi_ip4_interface_set_dns ++ }; +diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c +new file mode 100644 +index 000000000..952bda9fa +--- /dev/null ++++ b/grub-core/net/efi/ip6_config.c +@@ -0,0 +1,429 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++char * ++grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address) ++{ ++ char *str = grub_malloc (sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX")); ++ char *p; ++ int i; ++ int squash; ++ ++ if (!str) ++ return NULL; ++ ++ p = str; ++ squash = 0; ++ for (i = 0; i < 8; ++i) ++ { ++ grub_uint16_t addr; ++ ++ if (i == 7) ++ squash = 2; ++ ++ addr = grub_get_unaligned16 (address->addr + i * 2); ++ ++ if (grub_be_to_cpu16 (addr)) ++ { ++ char buf[sizeof ("XXXX")]; ++ if (i > 0) ++ *p++ = ':'; ++ grub_snprintf (buf, sizeof (buf), "%x", grub_be_to_cpu16 (addr)); ++ grub_strcpy (p, buf); ++ p += grub_strlen (buf); ++ ++ if (squash == 1) ++ squash = 2; ++ } ++ else ++ { ++ if (squash == 0) ++ { ++ *p++ = ':'; ++ squash = 1; ++ } ++ else if (squash == 2) ++ { ++ *p++ = ':'; ++ *p++ = '0'; ++ } ++ } ++ } ++ *p = '\0'; ++ return str; ++} ++ ++int ++grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest) ++{ ++ grub_uint16_t newip[8]; ++ const char *ptr = val; ++ int word, quaddot = -1; ++ int bracketed = 0; ++ ++ if (ptr[0] == '[') { ++ bracketed = 1; ++ ptr++; ++ } ++ ++ if (ptr[0] == ':' && ptr[1] != ':') ++ return 0; ++ if (ptr[0] == ':') ++ ptr++; ++ ++ for (word = 0; word < 8; word++) ++ { ++ unsigned long t; ++ if (*ptr == ':') ++ { ++ quaddot = word; ++ word--; ++ ptr++; ++ continue; ++ } ++ t = grub_strtoul (ptr, &ptr, 16); ++ if (grub_errno) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ break; ++ } ++ if (t & ~0xffff) ++ return 0; ++ newip[word] = grub_cpu_to_be16 (t); ++ if (*ptr != ':') ++ break; ++ ptr++; ++ } ++ if (quaddot == -1 && word < 7) ++ return 0; ++ if (quaddot != -1) ++ { ++ grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot], ++ (word - quaddot + 1) * sizeof (newip[0])); ++ grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); ++ } ++ grub_memcpy (address, newip, 16); ++ if (bracketed && *ptr == ']') { ++ ptr++; ++ } ++ if (rest) ++ *rest = ptr; ++ return 1; ++} ++ ++static grub_efi_ip6_config_interface_info_t * ++efi_ip6_config_interface_info (grub_efi_ip6_config_protocol_t *ip6_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ ++ sz = sizeof (*interface_info) + sizeof (*interface_info->route_table); ++ interface_info = grub_malloc (sz); ++ ++ status = ip6_config->get_data(ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (interface_info); ++ interface_info = grub_malloc (sz); ++ status = ip6_config->get_data(ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ return interface_info; ++} ++ ++static grub_efi_ip6_config_manual_address_t * ++efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = ip6_config->get_data(ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++char * ++grub_efi_ip6_interface_name (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ char *name; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE ++ * GRUB_MAX_UTF8_PER_UTF16 + 1); ++ *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name, ++ GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0; ++ grub_free (interface_info); ++ return name; ++} ++ ++static char * ++grub_efi_ip6_interface_hw_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ char *hw_addr; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address); ++ grub_free (interface_info); ++ ++ return hw_addr; ++} ++ ++static char * ++grub_efi_ip6_interface_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ char *addr; ++ ++ manual_address = efi_ip6_config_manual_address (dev->ip6_config); ++ ++ if (!manual_address) ++ return NULL; ++ ++ addr = grub_efi_ip6_address_to_string ((grub_efi_pxe_ipv6_address_t *)&manual_address->address); ++ grub_free (manual_address); ++ return addr; ++} ++ ++static char ** ++grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ char **ret; ++ int id; ++ grub_size_t i, nmemb; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ if (!interface_info) ++ return NULL; ++ ++ if (grub_add (interface_info->route_count, 1, &nmemb)) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ return NULL; ++ } ++ ++ ret = grub_calloc (nmemb, sizeof (*ret)); ++ if (!ret) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ id = 0; ++ for (i = 0; i < interface_info->route_count ; i++) ++ { ++ char *gateway, *destination; ++ grub_uint64_t u64_gateway[2]; ++ grub_uint64_t u64_destination[2]; ++ grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i; ++ grub_efi_net_interface_t *inf; ++ char *interface_name = NULL; ++ ++ gateway = grub_efi_ip6_address_to_string (&route_table->gateway); ++ destination = grub_efi_ip6_address_to_string (&route_table->destination); ++ ++ u64_gateway[0] = grub_get_unaligned64 (route_table->gateway.addr); ++ u64_gateway[1] = grub_get_unaligned64 (route_table->gateway.addr + 8); ++ u64_destination[0] = grub_get_unaligned64 (route_table->destination.addr); ++ u64_destination[1] = grub_get_unaligned64 (route_table->destination.addr + 8); ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6) ++ interface_name = inf->name; ++ ++ if ((!u64_gateway[0] && !u64_gateway[1]) ++ && (u64_destination[0] || u64_destination[1])) ++ { ++ if (interface_name) ++ { ++ if ((grub_be_to_cpu64 (u64_destination[0]) == 0xfe80000000000000ULL) ++ && (!u64_destination[1]) ++ && (route_table->prefix_length == 64)) ++ ret[id++] = grub_xasprintf ("%s:link %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); ++ else ++ ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); ++ } ++ } ++ else if ((u64_gateway[0] || u64_gateway[1]) ++ && (u64_destination[0] || u64_destination[1])) ++ ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); ++ else if ((u64_gateway[0] || u64_gateway[1]) ++ && (!u64_destination[0] && !u64_destination[1])) ++ ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); ++ ++ grub_free (gateway); ++ grub_free (destination); ++ } ++ ++ ret[id] = NULL; ++ grub_free (interface_info); ++ return ret; ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_ip6_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ grub_efi_net_interface_t *inf; ++ int i; ++ grub_efi_ipv6_address_t *address = &ip_address->ip6; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ if (!interface_info) ++ return NULL; ++ ++ for (i = 0; i < (int)interface_info->route_count ; i++) ++ { ++ grub_uint64_t u64_addr[2]; ++ grub_uint64_t u64_subnet[2]; ++ grub_uint64_t u64_mask[2]; ++ ++ grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i; ++ ++ /* SKIP Default GATEWAY */ ++ if (route_table->prefix_length == 0) ++ continue; ++ ++ u64_addr[0] = grub_get_unaligned64 (address); ++ u64_addr[1] = grub_get_unaligned64 (address + 4); ++ u64_subnet[0] = grub_get_unaligned64 (route_table->destination.addr); ++ u64_subnet[1] = grub_get_unaligned64 (route_table->destination.addr + 8); ++ u64_mask[0] = (route_table->prefix_length <= 64) ? ++ 0xffffffffffffffffULL << (64 - route_table->prefix_length) : ++ 0xffffffffffffffffULL; ++ u64_mask[1] = (route_table->prefix_length <= 64) ? ++ 0 : ++ 0xffffffffffffffffULL << (128 - route_table->prefix_length); ++ ++ if (((u64_addr[0] & u64_mask[0]) == u64_subnet[0]) ++ && ((u64_addr[1] & u64_mask[1]) == u64_subnet[1])) ++ { ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6) ++ { ++ grub_free (interface_info); ++ return inf; ++ } ++ } ++ } ++ ++ grub_free (interface_info); ++ return NULL; ++} ++ ++static int ++grub_efi_ip6_interface_set_manual_address (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int with_subnet) ++{ ++ grub_efi_status_t status; ++ grub_efi_ip6_config_manual_address_t *address = &net_ip->ip6; ++ ++ if (!with_subnet) ++ { ++ grub_efi_ip6_config_manual_address_t *manual_address = ++ efi_ip6_config_manual_address (dev->ip6_config); ++ ++ if (manual_address) ++ { ++ address->prefix_length = manual_address->prefix_length; ++ grub_free (manual_address); ++ } ++ else ++ { ++ /* XXX: */ ++ address->prefix_length = 64; ++ } ++ } ++ ++ status = dev->ip6_config->set_data(dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ sizeof(*address), address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ return 1; ++} ++ ++static int ++grub_efi_ip6_interface_set_gateway (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ grub_efi_status_t status; ++ ++ status = dev->ip6_config->set_data(dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY, ++ sizeof (address->ip6), &address->ip6); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++static int ++grub_efi_ip6_interface_set_dns (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ ++ grub_efi_status_t status; ++ ++ status = dev->ip6_config->set_data(dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ sizeof (address->ip6), &address->ip6); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++grub_efi_net_ip_config_t *efi_net_ip6_config = &(grub_efi_net_ip_config_t) ++ { ++ .get_hw_address = grub_efi_ip6_interface_hw_address, ++ .get_address = grub_efi_ip6_interface_address, ++ .get_route_table = grub_efi_ip6_interface_route_table, ++ .best_interface = grub_efi_ip6_interface_match, ++ .set_address = grub_efi_ip6_interface_set_manual_address, ++ .set_gateway = grub_efi_ip6_interface_set_gateway, ++ .set_dns = grub_efi_ip6_interface_set_dns ++ }; +diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c +new file mode 100644 +index 000000000..1b13603a6 +--- /dev/null ++++ b/grub-core/net/efi/net.c +@@ -0,0 +1,1436 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++#define GRUB_EFI_IP6_PREFIX_LENGTH 64 ++ ++static grub_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID; ++static grub_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID; ++static grub_guid_t http_service_binding_guid = GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; ++static grub_guid_t http_guid = GRUB_EFI_HTTP_PROTOCOL_GUID; ++static grub_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; ++static grub_guid_t dhcp4_service_binding_guid = GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID; ++static grub_guid_t dhcp4_guid = GRUB_EFI_DHCP4_PROTOCOL_GUID; ++static grub_guid_t dhcp6_service_binding_guid = GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID; ++static grub_guid_t dhcp6_guid = GRUB_EFI_DHCP6_PROTOCOL_GUID; ++ ++struct grub_efi_net_device *net_devices; ++ ++static char *default_server; ++static grub_efi_net_interface_t *net_interface; ++static grub_efi_net_interface_t *net_default_interface; ++ ++#define efi_net_interface_configure(inf) inf->io->configure (inf->dev, inf->prefer_ip6) ++#define efi_net_interface_open(inf, file, name) inf->io->open (inf->dev, inf->prefer_ip6, file, name, inf->io_type) ++#define efi_net_interface_read(inf, file, buf, sz) inf->io->read (inf->dev, inf->prefer_ip6, file, buf, sz) ++#define efi_net_interface_close(inf, file) inf->io->close (inf->dev, inf->prefer_ip6, file) ++#define efi_net_interface(m,...) efi_net_interface_ ## m (net_interface, ## __VA_ARGS__) ++ ++static grub_efi_handle_t ++grub_efi_locate_device_path (grub_guid_t *protocol, grub_efi_device_path_t *device_path, ++ grub_efi_device_path_t **r_device_path) ++{ ++ grub_efi_handle_t handle; ++ grub_efi_status_t status; ++ ++ status = grub_efi_system_table->boot_services->locate_device_path( ++ protocol, &device_path, &handle); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ if (r_device_path) ++ *r_device_path = device_path; ++ ++ return handle; ++} ++ ++static int ++url_parse_fields (const char *url, char **proto, char **host, char **path) ++{ ++ const char *p, *ps; ++ grub_size_t l; ++ ++ *proto = *host = *path = NULL; ++ ps = p = url; ++ ++ while ((p = grub_strchr (p, ':'))) ++ { ++ if (grub_strlen (p) < sizeof ("://") - 1) ++ break; ++ if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0) ++ { ++ l = p - ps; ++ *proto = grub_malloc (l + 1); ++ if (!*proto) ++ { ++ grub_print_error (); ++ return 0; ++ } ++ ++ grub_memcpy (*proto, ps, l); ++ (*proto)[l] = '\0'; ++ p += sizeof ("://") - 1; ++ break; ++ } ++ ++p; ++ } ++ ++ if (!*proto) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url); ++ return 0; ++ } ++ ++ ps = p; ++ p = grub_strchr (p, '/'); ++ ++ if (!p) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ ++ l = p - ps; ++ ++ if (l > 2 && ps[0] == '[' && ps[l - 1] == ']') ++ { ++ *host = grub_malloc (l - 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps + 1, l - 2); ++ (*host)[l - 2] = 0; ++ } ++ else ++ { ++ *host = grub_malloc (l + 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps, l); ++ (*host)[l] = 0; ++ } ++ ++ *path = grub_strdup (p); ++ if (!*path) ++ { ++ grub_print_error (); ++ grub_free (*host); ++ grub_free (*proto); ++ *host = NULL; ++ *proto = NULL; ++ return 0; ++ } ++ return 1; ++} ++ ++static void ++url_get_boot_location (const char *url, char **device, char **path, int is_default) ++{ ++ char *protocol, *server, *file; ++ char *slash; ++ ++ if (!url_parse_fields (url, &protocol, &server, &file)) ++ return; ++ ++ if ((slash = grub_strrchr (file, '/'))) ++ *slash = 0; ++ else ++ *file = 0; ++ ++ *device = grub_xasprintf ("%s,%s", protocol, server); ++ *path = grub_strdup(file); ++ ++ if (is_default) ++ default_server = server; ++ else ++ grub_free (server); ++ ++ grub_free (protocol); ++ grub_free (file); ++} ++ ++static void ++pxe_get_boot_location (const struct grub_net_bootp_packet *bp, ++ char **device, ++ char **path, ++ int is_default) ++{ ++ char *server = grub_xasprintf ("%d.%d.%d.%d", ++ ((grub_uint8_t *) &bp->server_ip)[0], ++ ((grub_uint8_t *) &bp->server_ip)[1], ++ ((grub_uint8_t *) &bp->server_ip)[2], ++ ((grub_uint8_t *) &bp->server_ip)[3]); ++ ++ *device = grub_xasprintf ("tftp,%s", server); ++ ++ *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file)); ++ ++ if (*path) ++ { ++ char *slash; ++ slash = grub_strrchr (*path, '/'); ++ if (slash) ++ *slash = 0; ++ else ++ **path = 0; ++ } ++ ++ if (is_default) ++ default_server = server; ++ else ++ grub_free (server); ++} ++ ++static void ++pxe_get_boot_location_v6 (const struct grub_net_dhcp6_packet *dp, ++ grub_size_t dhcp_size, ++ char **device, ++ char **path) ++{ ++ ++ struct grub_net_dhcp6_option *dhcp_opt; ++ grub_size_t dhcp_remain_size; ++ *device = *path = 0; ++ ++ if (dhcp_size < sizeof (*dp)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small")); ++ return; ++ } ++ ++ dhcp_remain_size = dhcp_size - sizeof (*dp); ++ dhcp_opt = (struct grub_net_dhcp6_option *)dp->dhcp_options; ++ ++ while (dhcp_remain_size) ++ { ++ grub_uint16_t code = grub_be_to_cpu16 (dhcp_opt->code); ++ grub_uint16_t len = grub_be_to_cpu16 (dhcp_opt->len); ++ grub_uint16_t option_size = sizeof (*dhcp_opt) + len; ++ ++ if (dhcp_remain_size < option_size || code == 0) ++ break; ++ ++ if (code == GRUB_NET_DHCP6_OPTION_BOOTFILE_URL) ++ { ++ char *url = grub_malloc (len + 1); ++ ++ grub_memcpy (url, dhcp_opt->data, len); ++ url[len] = 0; ++ ++ url_get_boot_location ((const char *)url, device, path, 1); ++ grub_free (url); ++ break; ++ } ++ ++ dhcp_remain_size -= option_size; ++ dhcp_opt = (struct grub_net_dhcp6_option *)((grub_uint8_t *)dhcp_opt + option_size); ++ } ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_net_config_from_device_path (grub_efi_device_path_t *dp, ++ struct grub_efi_net_device *netdev, ++ char **device, ++ char **path) ++{ ++ grub_efi_net_interface_t *inf = NULL; ++ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); ++ ++ if (type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) ++ { ++ if (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_uri_device_path_t *uri_dp; ++ uri_dp = (grub_efi_uri_device_path_t *) dp; ++ /* Beware that uri_dp->uri may not be null terminated */ ++ url_get_boot_location ((const char *)uri_dp->uri, device, path, 1); ++ } ++ else if (subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) dp; ++ ++ if (inf) ++ continue; ++ grub_memcpy (net_ip.ip4.address, ipv4->local_ip_address, sizeof (net_ip.ip4.address)); ++ grub_memcpy (net_ip.ip4.subnet_mask, ipv4->subnet_mask, sizeof (net_ip.ip4.subnet_mask)); ++ net_ip.is_ip6 = 0; ++ inf = grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1); ++ } ++ else if (subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) dp; ++ ++ if (inf) ++ continue; ++ grub_memcpy (net_ip.ip6.address, ipv6->local_ip_address, sizeof (net_ip.ip6.address)); ++ net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH; ++ net_ip.ip6.is_anycast = 0; ++ net_ip.is_ip6 = 1; ++ inf = grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1); ++ } ++ } ++ ++ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) ++ break; ++ dp = (grub_efi_device_path_t *) ((char *) dp + len); ++ } ++ ++ return inf; ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_net_config_from_handle (grub_efi_handle_t *hnd, ++ struct grub_efi_net_device *netdev, ++ char **device, ++ char **path) ++{ ++ grub_efi_pxe_t *pxe = NULL; ++ ++ if (hnd == netdev->ip4_pxe_handle) ++ pxe = netdev->ip4_pxe; ++ else if (hnd == netdev->ip6_pxe_handle) ++ pxe = netdev->ip6_pxe; ++ ++ if (!pxe) ++ return (grub_efi_net_config_from_device_path ( ++ grub_efi_get_device_path (hnd), ++ netdev, ++ device, ++ path)); ++ ++ if (pxe->mode->using_ipv6) ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ ++ pxe_get_boot_location_v6 ( ++ (const struct grub_net_dhcp6_packet *) &pxe->mode->dhcp_ack, ++ sizeof (pxe->mode->dhcp_ack), ++ device, ++ path); ++ ++ grub_memcpy (net_ip.ip6.address, pxe->mode->station_ip.v6, sizeof(net_ip.ip6.address)); ++ net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH; ++ net_ip.ip6.is_anycast = 0; ++ net_ip.is_ip6 = 1; ++ return (grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1)); ++ } ++ else ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ ++ pxe_get_boot_location ( ++ (const struct grub_net_bootp_packet *) &pxe->mode->dhcp_ack, ++ device, ++ path, ++ 1); ++ ++ grub_memcpy (net_ip.ip4.address, pxe->mode->station_ip.v4, sizeof (net_ip.ip4.address)); ++ grub_memcpy (net_ip.ip4.subnet_mask, pxe->mode->subnet_mask.v4, sizeof (net_ip.ip4.subnet_mask)); ++ net_ip.is_ip6 = 0; ++ return (grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1)); ++ } ++} ++ ++static const char * ++grub_efi_net_var_get_address (struct grub_env_var *var, ++ const char *val __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *var_name; ++ ++ var_name = grub_xasprintf ("net_%s_ip", inf->name); ++ if (grub_strcmp (var_name, var->name) == 0) ++ return efi_net_interface_get_address (inf); ++ grub_free (var_name); ++ var_name = grub_xasprintf ("net_%s_mac", inf->name); ++ if (grub_strcmp (var_name, var->name) == 0) ++ return efi_net_interface_get_hw_address (inf); ++ grub_free (var_name); ++ } ++ } ++ ++ return NULL; ++} ++ ++static char * ++grub_efi_net_var_set_interface (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ struct grub_efi_net_device *dev; ++ grub_efi_net_interface_t *inf; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (grub_strcmp (inf->name, val) == 0) ++ { ++ net_default_interface = inf; ++ return grub_strdup (val); ++ } ++ ++ return NULL; ++} ++ ++static char * ++grub_efi_net_var_set_server (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ grub_free (default_server); ++ default_server = grub_strdup (val); ++ return grub_strdup (val); ++} ++ ++static const char * ++grub_efi_net_var_get_server (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ return default_server ? : ""; ++} ++ ++static const char * ++grub_efi_net_var_get_ip (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ const char *intf = grub_env_get ("net_default_interface"); ++ const char *ret = NULL; ++ if (intf) ++ { ++ char *buf = grub_xasprintf ("net_%s_ip", intf); ++ if (buf) ++ ret = grub_env_get (buf); ++ grub_free (buf); ++ } ++ return ret; ++} ++ ++static const char * ++grub_efi_net_var_get_mac (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ const char *intf = grub_env_get ("net_default_interface"); ++ const char *ret = NULL; ++ if (intf) ++ { ++ char *buf = grub_xasprintf ("net_%s_mac", intf); ++ if (buf) ++ ret = grub_env_get (buf); ++ grub_free (buf); ++ } ++ return ret; ++} ++ ++static void ++grub_efi_net_export_interface_vars (void) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *var; ++ ++ var = grub_xasprintf ("net_%s_ip", inf->name); ++ grub_register_variable_hook (var, grub_efi_net_var_get_address, 0); ++ grub_env_export (var); ++ grub_free (var); ++ var = grub_xasprintf ("net_%s_mac", inf->name); ++ grub_register_variable_hook (var, grub_efi_net_var_get_address, 0); ++ grub_env_export (var); ++ grub_free (var); ++ } ++ } ++} ++ ++static void ++grub_efi_net_unset_interface_vars (void) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *var; ++ ++ var = grub_xasprintf ("net_%s_ip", inf->name); ++ grub_register_variable_hook (var, 0, 0); ++ grub_env_unset (var); ++ grub_free (var); ++ var = grub_xasprintf ("net_%s_mac", inf->name); ++ grub_register_variable_hook (var, 0, 0); ++ grub_env_unset (var); ++ grub_free (var); ++ } ++ } ++} ++ ++grub_efi_net_interface_t * ++grub_efi_net_create_interface (struct grub_efi_net_device *dev, ++ const char *interface_name, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int has_subnet) ++{ ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ if (inf->prefer_ip6 == net_ip->is_ip6) ++ break; ++ } ++ ++ if (!inf) ++ { ++ inf = grub_malloc (sizeof(*inf)); ++ inf->name = grub_strdup (interface_name); ++ inf->prefer_ip6 = net_ip->is_ip6; ++ inf->dev = dev; ++ inf->next = dev->net_interfaces; ++ inf->ip_config = (net_ip->is_ip6) ? efi_net_ip6_config : efi_net_ip4_config ; ++ dev->net_interfaces = inf; ++ } ++ else ++ { ++ grub_free (inf->name); ++ inf->name = grub_strdup (interface_name); ++ } ++ ++ if (!efi_net_interface_set_address (inf, net_ip, has_subnet)) ++ { ++ grub_error (GRUB_ERR_BUG, N_("Set Address Failed")); ++ return NULL; ++ } ++ ++ return inf; ++} ++ ++static void ++grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, ++ char **path) ++{ ++ grub_efi_handle_t config_hnd; ++ ++ struct grub_efi_net_device *netdev; ++ grub_efi_net_interface_t *inf; ++ ++ config_hnd = grub_efi_locate_device_path (&ip4_config_guid, grub_efi_get_device_path (hnd), NULL); ++ ++ if (!config_hnd) ++ return; ++ ++ for (netdev = net_devices; netdev; netdev = netdev->next) ++ if (netdev->handle == config_hnd) ++ break; ++ ++ if (!netdev) ++ return; ++ ++ if (!(inf = grub_efi_net_config_from_handle (hnd, netdev, device, path))) ++ return; ++ ++ grub_env_set ("net_default_interface", inf->name); ++ grub_efi_net_export_interface_vars (); ++} ++ ++static grub_err_t ++grub_efi_netfs_dir (grub_device_t device, const char *path __attribute__ ((unused)), ++ grub_fs_dir_hook_t hook __attribute__ ((unused)), ++ void *hook_data __attribute__ ((unused))) ++{ ++ if (!device->net) ++ return grub_error (GRUB_ERR_BUG, "invalid net device"); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_efi_netfs_open (struct grub_file *file_out __attribute__ ((unused)), ++ const char *name __attribute__ ((unused))) ++{ ++ struct grub_file *file, *bufio; ++ ++ file = grub_malloc (sizeof (*file)); ++ if (!file) ++ return grub_errno; ++ ++ grub_memcpy (file, file_out, sizeof (struct grub_file)); ++ file->device->net->name = grub_strdup (name); ++ ++ if (!file->device->net->name) ++ { ++ grub_free (file); ++ return grub_errno; ++ } ++ ++ efi_net_interface(open, file, name); ++ grub_print_error (); ++ ++ bufio = grub_bufio_open (file, 32768); ++ if (!bufio) ++ { ++ grub_free (file->device->net->name); ++ grub_free (file); ++ return grub_errno; ++ } ++ grub_memcpy (file_out, bufio, sizeof (struct grub_file)); ++ grub_free (bufio); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++grub_efihttp_chunk_read (grub_file_t file, char *buf, ++ grub_size_t len, grub_size_t chunk_size) ++{ ++ char *chunk = grub_malloc (chunk_size); ++ grub_size_t sum = 0; ++ ++ while (len) ++ { ++ grub_ssize_t rd; ++ grub_size_t sz = (len > chunk_size) ? chunk_size : len; ++ ++ rd = efi_net_interface (read, file, chunk, sz); ++ ++ if (rd <= 0) { ++ grub_free (chunk); ++ return rd; ++ } ++ ++ if (buf) ++ { ++ grub_memcpy (buf, chunk, rd); ++ buf += rd; ++ } ++ sum += rd; ++ len -= rd; ++ } ++ ++ grub_free (chunk); ++ return sum; ++} ++ ++static grub_ssize_t ++grub_efi_netfs_read (grub_file_t file __attribute__ ((unused)), ++ char *buf __attribute__ ((unused)), grub_size_t len __attribute__ ((unused))) ++{ ++ if (file->offset > file->device->net->offset) ++ { ++ grub_efihttp_chunk_read (file, NULL, file->offset - file->device->net->offset, 10240); ++ } ++ else if (file->offset < file->device->net->offset) ++ { ++ efi_net_interface (close, file); ++ efi_net_interface (open, file, file->device->net->name); ++ if (file->offset) ++ grub_efihttp_chunk_read (file, NULL, file->offset, 10240); ++ } ++ ++ return efi_net_interface (read, file, buf, len); ++} ++ ++static grub_err_t ++grub_efi_netfs_close (grub_file_t file) ++{ ++ efi_net_interface (close, file); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_efi_handle_t ++grub_efi_service_binding (grub_efi_handle_t dev, grub_guid_t *service_binding_guid) ++{ ++ grub_efi_service_binding_t *service; ++ grub_efi_status_t status; ++ grub_efi_handle_t child_dev = NULL; ++ ++ service = grub_efi_open_protocol (dev, service_binding_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!service) ++ { ++ grub_error (GRUB_ERR_IO, N_("couldn't open efi service binding protocol")); ++ return NULL; ++ } ++ ++ status = service->create_child(service, &child_dev); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_IO, N_("Failed to create child device of http service %x"), (unsigned) status); ++ return NULL; ++ } ++ ++ return child_dev; ++} ++ ++static grub_err_t ++grub_efi_net_parse_address (const char *address, ++ grub_efi_ip4_config2_manual_address_t *ip4, ++ grub_efi_ip6_config_manual_address_t *ip6, ++ int *is_ip6, ++ int *has_cidr) ++{ ++ const char *rest; ++ ++ if (grub_efi_string_to_ip4_address (address, &ip4->address, &rest)) ++ { ++ *is_ip6 = 0; ++ if (*rest == '/') ++ { ++ grub_uint32_t subnet_mask_size; ++ ++ subnet_mask_size = grub_strtoul (rest + 1, &rest, 0); ++ ++ if (!grub_errno && subnet_mask_size <= 32 && *rest == 0) ++ { ++ grub_uint32_t subnet_mask; ++ ++ subnet_mask = grub_cpu_to_be32 ((0xffffffffU << (32 - subnet_mask_size))); ++ grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); ++ if (has_cidr) ++ *has_cidr = 1; ++ return GRUB_ERR_NONE; ++ } ++ } ++ else if (*rest == 0 || *rest == ':') ++ { ++ grub_uint32_t subnet_mask = 0xffffffffU; ++ grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); ++ if (has_cidr) ++ *has_cidr = 0; ++ return GRUB_ERR_NONE; ++ } ++ } ++ else if (grub_efi_string_to_ip6_address (address, &ip6->address, &rest)) ++ { ++ *is_ip6 = 1; ++ if (*rest == '/') ++ { ++ grub_efi_uint8_t prefix_length; ++ ++ prefix_length = grub_strtoul (rest + 1, &rest, 0); ++ if (!grub_errno && prefix_length <= 128 && *rest == 0) ++ { ++ ip6->prefix_length = prefix_length; ++ ip6->is_anycast = 0; ++ if (has_cidr) ++ *has_cidr = 1; ++ return GRUB_ERR_NONE; ++ } ++ } ++ else if (*rest == 0 || *rest == ':') ++ { ++ ip6->prefix_length = 128; ++ ip6->is_anycast = 0; ++ if (has_cidr) ++ *has_cidr = 0; ++ return GRUB_ERR_NONE; ++ } ++ } ++ ++ grub_dprintf ("efinet", "unrecognised network address '%s'\n", address); ++ ++ return GRUB_ERR_NET_BAD_ADDRESS; ++} ++ ++static grub_efi_net_interface_t * ++match_route (const char *server) ++{ ++ grub_err_t err; ++ grub_efi_ip4_config2_manual_address_t ip4; ++ grub_efi_ip6_config_manual_address_t ip6; ++ grub_efi_net_interface_t *inf; ++ int is_ip6 = 0; ++ ++ err = grub_efi_net_parse_address (server, &ip4, &ip6, &is_ip6, 0); ++ ++ if (err) ++ return NULL; ++ ++ if (is_ip6) ++ { ++ struct grub_efi_net_device *dev; ++ grub_efi_net_ip_address_t addr; ++ ++ grub_memcpy (addr.ip6, ip6.address, sizeof(ip6.address)); ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ if ((inf = efi_net_ip6_config->best_interface (dev, &addr))) ++ return inf; ++ } ++ else ++ { ++ struct grub_efi_net_device *dev; ++ grub_efi_net_ip_address_t addr; ++ ++ grub_memcpy (addr.ip4, ip4.address, sizeof(ip4.address)); ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ if ((inf = efi_net_ip4_config->best_interface (dev, &addr))) ++ return inf; ++ } ++ ++ return 0; ++} ++ ++static void ++grub_efi_net_add_pxebc_to_cards (void) ++{ ++ grub_efi_uintn_t num_handles; ++ grub_efi_handle_t *handles; ++ grub_efi_handle_t *handle; ++ ++ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &pxe_io_guid, ++ 0, &num_handles); ++ if (!handles) ++ return; ++ ++ for (handle = handles; num_handles--; handle++) ++ { ++ grub_efi_device_path_t *dp, *ddp, *ldp; ++ grub_efi_pxe_t *pxe; ++ struct grub_efi_net_device *d; ++ int is_ip6 = 0; ++ ++ dp = grub_efi_get_device_path (*handle); ++ if (!dp) ++ continue; ++ ++ ddp = grub_efi_duplicate_device_path (dp); ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ && ldp->subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) ++ { ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ } ++ else if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ && ldp->subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) ++ { ++ is_ip6 = 1; ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ } ++ ++ for (d = net_devices; d; d = d->next) ++ if (grub_efi_compare_device_paths (ddp, grub_efi_get_device_path (d->handle)) == 0) ++ break; ++ ++ if (!d) ++ { ++ grub_free (ddp); ++ continue; ++ } ++ ++ pxe = grub_efi_open_protocol (*handle, &pxe_io_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ if (!pxe) ++ { ++ grub_free (ddp); ++ continue; ++ } ++ ++ if (is_ip6) ++ { ++ d->ip6_pxe_handle = *handle; ++ d->ip6_pxe = pxe; ++ } ++ else ++ { ++ d->ip4_pxe_handle = *handle; ++ d->ip4_pxe = pxe; ++ } ++ ++ grub_free (ddp); ++ } ++ ++ grub_free (handles); ++} ++ ++static void ++set_ip_policy_to_static (void) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_ip4_config2_policy_t ip4_policy = GRUB_EFI_IP4_CONFIG2_POLICY_STATIC; ++ ++ if (dev->ip4_config->set_data(dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY, ++ sizeof (ip4_policy), &ip4_policy) != GRUB_EFI_SUCCESS) ++ grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP4_CONFIG2_POLICY_STATIC on dev `%s'", dev->card_name); ++ ++ if (dev->ip6_config) ++ { ++ grub_efi_ip6_config_policy_t ip6_policy = GRUB_EFI_IP6_CONFIG_POLICY_MANUAL; ++ ++ if (dev->ip6_config->set_data(dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY, ++ sizeof (ip6_policy), &ip6_policy) != GRUB_EFI_SUCCESS) ++ grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP6_CONFIG_POLICY_MANUAL on dev `%s'", dev->card_name); ++ } ++ } ++} ++ ++/* FIXME: Do not fail if the card did not support any of the protocol (Eg http) */ ++static void ++grub_efi_net_find_cards (void) ++{ ++ grub_efi_uintn_t num_handles; ++ grub_efi_handle_t *handles; ++ grub_efi_handle_t *handle; ++ int id; ++ ++ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &ip4_config_guid, ++ 0, &num_handles); ++ if (!handles) ++ return; ++ ++ for (id = 0, handle = handles; num_handles--; handle++, id++) ++ { ++ grub_efi_device_path_t *dp; ++ grub_efi_ip4_config2_protocol_t *ip4_config; ++ grub_efi_ip6_config_protocol_t *ip6_config; ++ grub_efi_handle_t http_handle; ++ grub_efi_http_t *http; ++ grub_efi_handle_t dhcp4_handle; ++ grub_efi_dhcp4_protocol_t *dhcp4; ++ grub_efi_handle_t dhcp6_handle; ++ grub_efi_dhcp6_protocol_t *dhcp6; ++ ++ struct grub_efi_net_device *d; ++ ++ dp = grub_efi_get_device_path (*handle); ++ if (!dp) ++ continue; ++ ++ ip4_config = grub_efi_open_protocol (*handle, &ip4_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!ip4_config) ++ continue; ++ ++ ip6_config = grub_efi_open_protocol (*handle, &ip6_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ http_handle = grub_efi_service_binding (*handle, &http_service_binding_guid); ++ grub_errno = GRUB_ERR_NONE; ++ http = (http_handle) ++ ? grub_efi_open_protocol (http_handle, &http_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) ++ : NULL; ++ ++ dhcp4_handle = grub_efi_service_binding (*handle, &dhcp4_service_binding_guid); ++ grub_errno = GRUB_ERR_NONE; ++ dhcp4 = (dhcp4_handle) ++ ? grub_efi_open_protocol (dhcp4_handle, &dhcp4_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) ++ : NULL; ++ ++ ++ dhcp6_handle = grub_efi_service_binding (*handle, &dhcp6_service_binding_guid); ++ grub_errno = GRUB_ERR_NONE; ++ dhcp6 = (dhcp6_handle) ++ ? grub_efi_open_protocol (dhcp6_handle, &dhcp6_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) ++ : NULL; ++ ++ d = grub_malloc (sizeof (*d)); ++ if (!d) ++ { ++ grub_free (handles); ++ while (net_devices) ++ { ++ d = net_devices->next; ++ grub_free (net_devices); ++ net_devices = d; ++ } ++ return; ++ } ++ d->handle = *handle; ++ d->ip4_config = ip4_config; ++ d->ip6_config = ip6_config; ++ d->http_handle = http_handle; ++ d->http = http; ++ d->dhcp4_handle = dhcp4_handle; ++ d->dhcp4 = dhcp4; ++ d->dhcp6_handle = dhcp6_handle; ++ d->dhcp6 = dhcp6; ++ d->next = net_devices; ++ d->card_name = grub_xasprintf ("efinet%d", id); ++ d->net_interfaces = NULL; ++ net_devices = d; ++ } ++ ++ grub_efi_net_add_pxebc_to_cards (); ++ grub_free (handles); ++ set_ip_policy_to_static (); ++} ++ ++static void ++listroutes_ip4 (struct grub_efi_net_device *netdev) ++{ ++ char **routes; ++ ++ routes = NULL; ++ ++ if ((routes = efi_net_ip4_config->get_route_table (netdev))) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_printf ("%s\n", *r); ++ } ++ ++ if (routes) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_free (*r); ++ grub_free (routes); ++ } ++} ++ ++static void ++listroutes_ip6 (struct grub_efi_net_device *netdev) ++{ ++ char **routes; ++ ++ routes = NULL; ++ ++ if ((routes = efi_net_ip6_config->get_route_table (netdev))) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_printf ("%s\n", *r); ++ } ++ ++ if (routes) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_free (*r); ++ grub_free (routes); ++ } ++} ++ ++static grub_err_t ++grub_cmd_efi_listroutes (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *netdev; ++ ++ for (netdev = net_devices; netdev; netdev = netdev->next) ++ { ++ listroutes_ip4 (netdev); ++ listroutes_ip6 (netdev); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++static grub_err_t ++grub_cmd_efi_listcards (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ char *hw_addr; ++ ++ hw_addr = efi_net_ip4_config->get_hw_address (dev); ++ ++ if (hw_addr) ++ { ++ grub_printf ("%s %s\n", dev->card_name, hw_addr); ++ grub_free (hw_addr); ++ } ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_efi_listaddrs (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ grub_efi_net_interface_t *inf; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *hw_addr = NULL; ++ char *addr = NULL; ++ ++ if ((hw_addr = efi_net_interface_get_hw_address (inf)) ++ && (addr = efi_net_interface_get_address (inf))) ++ grub_printf ("%s %s %s\n", inf->name, hw_addr, addr); ++ ++ if (hw_addr) ++ grub_free (hw_addr); ++ if (addr) ++ grub_free (addr); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* FIXME: support MAC specifying. */ ++static grub_err_t ++grub_cmd_efi_addaddr (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, char **args) ++{ ++ struct grub_efi_net_device *dev; ++ grub_err_t err; ++ grub_efi_ip4_config2_manual_address_t ip4; ++ grub_efi_ip6_config_manual_address_t ip6; ++ grub_efi_net_ip_manual_address_t net_ip; ++ int is_ip6 = 0; ++ int cidr = 0; ++ ++ if (argc != 3) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("three arguments expected")); ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ if (grub_strcmp (dev->card_name, args[1]) == 0) ++ break; ++ } ++ ++ if (!dev) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("card not found")); ++ ++ err = grub_efi_net_parse_address (args[2], &ip4, &ip6, &is_ip6, &cidr); ++ ++ if (err) ++ return err; ++ ++ net_ip.is_ip6 = is_ip6; ++ if (is_ip6) ++ grub_memcpy (&net_ip.ip6, &ip6, sizeof(net_ip.ip6)); ++ else ++ grub_memcpy (&net_ip.ip4, &ip4, sizeof(net_ip.ip4)); ++ ++ if (!grub_efi_net_create_interface (dev, ++ args[0], ++ &net_ip, ++ cidr)) ++ return grub_errno; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static struct grub_fs grub_efi_netfs; ++ ++static grub_net_t ++grub_net_open_real (const char *name __attribute__ ((unused))) ++{ ++ grub_size_t protnamelen; ++ const char *protname, *server; ++ grub_net_t ret; ++ ++ net_interface = NULL; ++ ++ if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) ++ { ++ protname = "tftp"; ++ protnamelen = sizeof ("tftp") - 1; ++ server = name + sizeof ("pxe:") - 1; ++ } ++ else if (grub_strcmp (name, "pxe") == 0) ++ { ++ protname = "tftp"; ++ protnamelen = sizeof ("tftp") - 1; ++ server = default_server; ++ } ++ else ++ { ++ const char *comma; ++ ++ comma = grub_strchr (name, ','); ++ if (comma) ++ { ++ protnamelen = comma - name; ++ server = comma + 1; ++ protname = name; ++ } ++ else ++ { ++ protnamelen = grub_strlen (name); ++ server = default_server; ++ protname = name; ++ } ++ } ++ ++ if (!server) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("no server is specified")); ++ return NULL; ++ } ++ ++ /*FIXME: Use DNS translate name to address */ ++ net_interface = match_route (server); ++ ++ if (!net_interface && net_default_interface) ++ { ++ net_interface = net_default_interface; ++ grub_dprintf ("efinet", "interface lookup failed, using default '%s'\n", ++ net_interface->name); ++ } ++ ++ /*XXX: should we check device with default gateway ? */ ++ if (!net_interface) ++ { ++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' no route found"), ++ name); ++ return NULL; ++ } ++ ++ if ((protnamelen == (sizeof ("https") - 1) ++ && grub_memcmp ("https", protname, protnamelen) == 0)) ++ { ++ net_interface->io = &io_http; ++ net_interface->io_type = 1; ++ } ++ else if ((protnamelen == (sizeof ("http") - 1) ++ && grub_memcmp ("http", protname, protnamelen) == 0)) ++ { ++ net_interface->io = &io_http; ++ net_interface->io_type = 0; ++ } ++ else if (protnamelen == (sizeof ("tftp") - 1) ++ && grub_memcmp ("tftp", protname, protnamelen) == 0) ++ { ++ net_interface->io = &io_pxe; ++ net_interface->io_type = 0; ++ } ++ else ++ { ++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"), ++ name); ++ return NULL; ++ } ++ ++ /*XXX: Should we try to avoid doing excess "reconfigure" here ??? */ ++ efi_net_interface (configure); ++ ++ ret = grub_zalloc (sizeof (*ret)); ++ if (!ret) ++ return NULL; ++ ++ ret->server = grub_strdup (server); ++ if (!ret->server) ++ { ++ grub_free (ret); ++ return NULL; ++ } ++ ++ ret->fs = &grub_efi_netfs; ++ return ret; ++} ++#if 0 ++static grub_command_t cmd_efi_lsaddr; ++static grub_command_t cmd_efi_lscards; ++static grub_command_t cmd_efi_lsroutes; ++static grub_command_t cmd_efi_addaddr; ++#endif ++ ++static struct grub_fs grub_efi_netfs = ++ { ++ .name = "efi netfs", ++ .fs_dir = grub_efi_netfs_dir, ++ .fs_open = grub_efi_netfs_open, ++ .fs_read = grub_efi_netfs_read, ++ .fs_close = grub_efi_netfs_close, ++ .fs_label = NULL, ++ .fs_uuid = NULL, ++ .fs_mtime = NULL, ++ }; ++ ++int ++grub_efi_net_boot_from_https (void) ++{ ++ grub_efi_loaded_image_t *image = NULL; ++ grub_efi_device_path_t *dp; ++ ++ image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (!image) ++ return 0; ++ ++ dp = grub_efi_get_device_path (image->device_handle); ++ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); ++ ++ if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) ++ && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) ++ { ++ grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp; ++ grub_dprintf ("efinet", "url:%s\n", (const char *)uri_dp->uri); ++ return (grub_strncmp ((const char *)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0 || ++ grub_strncmp ((const char *)uri_dp->uri, "http://", sizeof ("http://") - 1) == 0); ++ } ++ ++ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) ++ break; ++ dp = (grub_efi_device_path_t *) ((char *) dp + len); ++ } ++ ++ return 0; ++} ++ ++int ++grub_efi_net_boot_from_opa (void) ++{ ++ grub_efi_loaded_image_t *image = NULL; ++ grub_efi_device_path_t *dp; ++ ++ image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (!image) ++ return 0; ++ ++ dp = grub_efi_get_device_path (image->device_handle); ++ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); ++ ++ if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) ++ && (subtype == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)) ++ { ++ grub_efi_mac_address_device_path_t *mac_dp = (grub_efi_mac_address_device_path_t *)dp; ++ return (mac_dp->if_type == 0xC7) ? 1 : 0; ++ } ++ ++ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) ++ break; ++ dp = (grub_efi_device_path_t *) ((char *) dp + len); ++ } ++ ++ return 0; ++} ++ ++static char * ++grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ return NULL; ++} ++ ++grub_command_func_t grub_efi_net_list_routes = grub_cmd_efi_listroutes; ++grub_command_func_t grub_efi_net_list_cards = grub_cmd_efi_listcards; ++grub_command_func_t grub_efi_net_list_addrs = grub_cmd_efi_listaddrs; ++grub_command_func_t grub_efi_net_add_addr = grub_cmd_efi_addaddr; ++ ++int ++grub_efi_net_fs_init () ++{ ++ grub_efi_net_find_cards (); ++ grub_efi_net_config = grub_efi_net_config_real; ++ grub_net_open = grub_net_open_real; ++ grub_register_variable_hook ("net_default_server", grub_efi_net_var_get_server, ++ grub_efi_net_var_set_server); ++ grub_env_export ("net_default_server"); ++ grub_register_variable_hook ("pxe_default_server", grub_efi_net_var_get_server, ++ grub_efi_net_var_set_server); ++ grub_env_export ("pxe_default_server"); ++ grub_register_variable_hook ("net_default_interface", 0, ++ grub_efi_net_var_set_interface); ++ grub_env_export ("net_default_interface"); ++ grub_register_variable_hook ("net_default_ip", grub_efi_net_var_get_ip, ++ 0); ++ grub_env_export ("net_default_ip"); ++ grub_register_variable_hook ("net_default_mac", grub_efi_net_var_get_mac, ++ 0); ++ grub_env_export ("net_default_mac"); ++ ++ grub_env_set ("grub_netfs_type", "efi"); ++ grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly); ++ grub_env_export ("grub_netfs_type"); ++ ++ return 1; ++} ++ ++void ++grub_efi_net_fs_fini (void) ++{ ++ grub_env_unset ("grub_netfs_type"); ++ grub_efi_net_unset_interface_vars (); ++ grub_register_variable_hook ("net_default_server", 0, 0); ++ grub_env_unset ("net_default_server"); ++ grub_register_variable_hook ("net_default_interface", 0, 0); ++ grub_env_unset ("net_default_interface"); ++ grub_register_variable_hook ("pxe_default_server", 0, 0); ++ grub_env_unset ("pxe_default_server"); ++ grub_register_variable_hook ("net_default_ip", 0, 0); ++ grub_env_unset ("net_default_ip"); ++ grub_register_variable_hook ("net_default_mac", 0, 0); ++ grub_env_unset ("net_default_mac"); ++ grub_efi_net_config = NULL; ++ grub_net_open = NULL; ++ grub_fs_unregister (&grub_efi_netfs); ++} +diff --git a/grub-core/net/efi/pxe.c b/grub-core/net/efi/pxe.c +new file mode 100644 +index 000000000..e828fb23e +--- /dev/null ++++ b/grub-core/net/efi/pxe.c +@@ -0,0 +1,424 @@ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static grub_efi_ip6_config_manual_address_t * ++efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = ip6_config->get_data(ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++static grub_efi_ip4_config2_manual_address_t * ++efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = ip4_config->get_data(ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++static void ++pxe_configure (struct grub_efi_net_device *dev, int prefer_ip6) ++{ ++ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; ++ ++ grub_efi_pxe_mode_t *mode = pxe->mode; ++ ++ if (!mode->started) ++ { ++ grub_efi_status_t status; ++ status = pxe->start(pxe, prefer_ip6); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't start PXE\n"); ++ } ++ ++#if 0 ++ grub_printf ("PXE STARTED: %u\n", mode->started); ++ grub_printf ("PXE USING IPV6: %u\n", mode->using_ipv6); ++#endif ++ ++ if (mode->using_ipv6) ++ { ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ manual_address = efi_ip6_config_manual_address (dev->ip6_config); ++ ++ if (manual_address && ++ grub_memcmp (manual_address->address, mode->station_ip.v6, sizeof (manual_address->address)) != 0) ++ { ++ grub_efi_status_t status; ++ grub_efi_pxe_ip_address_t station_ip; ++ ++ grub_memcpy (station_ip.v6.addr, manual_address->address, sizeof (station_ip.v6.addr)); ++ status = pxe->set_station_ip(pxe, &station_ip, NULL); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't set station ip\n"); ++ ++ grub_free (manual_address); ++ } ++ } ++ else ++ { ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ manual_address = efi_ip4_config_manual_address (dev->ip4_config); ++ ++ if (manual_address && ++ grub_memcmp (manual_address->address, mode->station_ip.v4, sizeof (manual_address->address)) != 0) ++ { ++ grub_efi_status_t status; ++ grub_efi_pxe_ip_address_t station_ip; ++ grub_efi_pxe_ip_address_t subnet_mask; ++ ++ grub_memcpy (station_ip.v4.addr, manual_address->address, sizeof (station_ip.v4.addr)); ++ grub_memcpy (subnet_mask.v4.addr, manual_address->subnet_mask, sizeof (subnet_mask.v4.addr)); ++ ++ status = pxe->set_station_ip(pxe, &station_ip, &subnet_mask); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't set station ip\n"); ++ ++ grub_free (manual_address); ++ } ++ } ++ ++#if 0 ++ if (mode->using_ipv6) ++ { ++ grub_printf ("PXE STATION IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", ++ mode->station_ip.v6.addr[0], ++ mode->station_ip.v6.addr[1], ++ mode->station_ip.v6.addr[2], ++ mode->station_ip.v6.addr[3], ++ mode->station_ip.v6.addr[4], ++ mode->station_ip.v6.addr[5], ++ mode->station_ip.v6.addr[6], ++ mode->station_ip.v6.addr[7], ++ mode->station_ip.v6.addr[8], ++ mode->station_ip.v6.addr[9], ++ mode->station_ip.v6.addr[10], ++ mode->station_ip.v6.addr[11], ++ mode->station_ip.v6.addr[12], ++ mode->station_ip.v6.addr[13], ++ mode->station_ip.v6.addr[14], ++ mode->station_ip.v6.addr[15]); ++ } ++ else ++ { ++ grub_printf ("PXE STATION IP: %d.%d.%d.%d\n", ++ mode->station_ip.v4.addr[0], ++ mode->station_ip.v4.addr[1], ++ mode->station_ip.v4.addr[2], ++ mode->station_ip.v4.addr[3]); ++ grub_printf ("PXE SUBNET MASK: %d.%d.%d.%d\n", ++ mode->subnet_mask.v4.addr[0], ++ mode->subnet_mask.v4.addr[1], ++ mode->subnet_mask.v4.addr[2], ++ mode->subnet_mask.v4.addr[3]); ++ } ++#endif ++ ++ /* TODO: Set The Station IP to the IP2 Config */ ++} ++ ++static int ++parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) ++{ ++ grub_uint16_t newip[8]; ++ const char *ptr = val; ++ int word, quaddot = -1; ++ int bracketed = 0; ++ ++ if (ptr[0] == '[') { ++ bracketed = 1; ++ ptr++; ++ } ++ ++ if (ptr[0] == ':' && ptr[1] != ':') ++ return 0; ++ if (ptr[0] == ':') ++ ptr++; ++ ++ for (word = 0; word < 8; word++) ++ { ++ unsigned long t; ++ if (*ptr == ':') ++ { ++ quaddot = word; ++ word--; ++ ptr++; ++ continue; ++ } ++ t = grub_strtoul (ptr, &ptr, 16); ++ if (grub_errno) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ break; ++ } ++ if (t & ~0xffff) ++ return 0; ++ newip[word] = grub_cpu_to_be16 (t); ++ if (*ptr != ':') ++ break; ++ ptr++; ++ } ++ if (quaddot == -1 && word < 7) ++ return 0; ++ if (quaddot != -1) ++ { ++ grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot], ++ (word - quaddot + 1) * sizeof (newip[0])); ++ grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); ++ } ++ grub_memcpy (ip, newip, 16); ++ if (bracketed && *ptr == ']') { ++ ptr++; ++ } ++ if (rest) ++ *rest = ptr; ++ return 1; ++} ++ ++static grub_err_t ++pxe_open (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ const char *filename, ++ int type __attribute__((unused))) ++{ ++ int i; ++ const char *p; ++ grub_efi_status_t status; ++ grub_efi_pxe_ip_address_t server_ip; ++ grub_efi_uint64_t file_size = 0; ++ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; ++ ++ if (pxe->mode->using_ipv6) ++ { ++ const char *rest; ++ grub_uint64_t ip6[2]; ++ if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0) ++ grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr)); ++ /* TODO: ERROR Handling Here */ ++#if 0 ++ grub_printf ("PXE SERVER IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", ++ server_ip.v6.addr[0], ++ server_ip.v6.addr[1], ++ server_ip.v6.addr[2], ++ server_ip.v6.addr[3], ++ server_ip.v6.addr[4], ++ server_ip.v6.addr[5], ++ server_ip.v6.addr[6], ++ server_ip.v6.addr[7], ++ server_ip.v6.addr[8], ++ server_ip.v6.addr[9], ++ server_ip.v6.addr[10], ++ server_ip.v6.addr[11], ++ server_ip.v6.addr[12], ++ server_ip.v6.addr[13], ++ server_ip.v6.addr[14], ++ server_ip.v6.addr[15]); ++#endif ++ } ++ else ++ { ++ for (i = 0, p = file->device->net->server; i < 4; ++i, ++p) ++ server_ip.v4.addr[i] = grub_strtoul (p, &p, 10); ++ } ++ ++ status = pxe->mtftp( ++ pxe, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, ++ NULL, ++ 0, ++ &file_size, ++ NULL, ++ &server_ip, ++ (grub_efi_char8_t *)filename, ++ NULL, ++ 0); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return grub_error (GRUB_ERR_IO, "Couldn't get file size"); ++ ++ file->size = (grub_off_t)file_size; ++ file->not_easily_seekable = 0; ++ file->data = 0; ++ file->device->net->offset = 0; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++pxe_close (struct grub_efi_net_device *dev __attribute__((unused)), ++ int prefer_ip6 __attribute__((unused)), ++ grub_file_t file __attribute__((unused))) ++{ ++ file->offset = 0; ++ file->size = 0; ++ file->device->net->offset = 0; ++ ++ if (file->data) ++ { ++ grub_free (file->data); ++ file->data = NULL; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++pxe_read (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ char *buf, ++ grub_size_t len) ++{ ++ int i; ++ const char *p; ++ grub_efi_status_t status; ++ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; ++ grub_efi_uint64_t bufsz = len; ++ grub_efi_pxe_ip_address_t server_ip; ++ char *buf2 = NULL; ++ ++ if (file->data) ++ { ++ /* TODO: RANGE Check for offset and file size */ ++ grub_memcpy (buf, (char*)file->data + file->device->net->offset, len); ++ file->device->net->offset += len; ++ return len; ++ } ++ ++ if (file->device->net->offset) ++ { ++ grub_error (GRUB_ERR_BUG, "No Offet Read Possible"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ if (pxe->mode->using_ipv6) ++ { ++ const char *rest; ++ grub_uint64_t ip6[2]; ++ if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0) ++ grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr)); ++ /* TODO: ERROR Handling Here */ ++ } ++ else ++ { ++ for (i = 0, p = file->device->net->server; i < 4; ++i, ++p) ++ server_ip.v4.addr[i] = grub_strtoul (p, &p, 10); ++ } ++ ++ status = pxe->mtftp( ++ pxe, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, ++ buf, ++ 0, ++ &bufsz, ++ NULL, ++ &server_ip, ++ (grub_efi_char8_t *)file->device->net->name, ++ NULL, ++ 0); ++ ++ if (bufsz != file->size) ++ { ++ grub_error (GRUB_ERR_BUG, "Short read should not happen here"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ ++ buf2 = grub_malloc (bufsz); ++ ++ if (!buf2) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "ERROR OUT OF MEMORY"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ status = pxe->mtftp( ++ pxe, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, ++ buf2, ++ 0, ++ &bufsz, ++ NULL, ++ &server_ip, ++ (grub_efi_char8_t *)file->device->net->name, ++ NULL, ++ 0); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ if (buf2) ++ grub_free (buf2); ++ ++ grub_error (GRUB_ERR_IO, "Failed to Read File"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ if (buf2) ++ grub_memcpy (buf, buf2, len); ++ ++ file->device->net->offset = len; ++ ++ if (buf2) ++ file->data = buf2; ++ ++ return len; ++} ++ ++struct grub_efi_net_io io_pxe = ++ { ++ .configure = pxe_configure, ++ .open = pxe_open, ++ .read = pxe_read, ++ .close = pxe_close ++ }; ++ +diff --git a/grub-core/net/ethernet.c b/grub-core/net/ethernet.c +index 707bbb12c..1441a1bac 100644 +--- a/grub-core/net/ethernet.c ++++ b/grub-core/net/ethernet.c +@@ -29,13 +29,6 @@ + + #define LLCADDRMASK 0x7f + +-struct etherhdr +-{ +- grub_uint8_t dst[6]; +- grub_uint8_t src[6]; +- grub_uint16_t type; +-} GRUB_PACKED; +- + struct llchdr + { + grub_uint8_t dsap; +@@ -55,13 +48,15 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf, + grub_net_link_level_address_t target_addr, + grub_net_ethertype_t ethertype) + { +- struct etherhdr *eth; ++ grub_uint8_t *eth; + grub_err_t err; +- grub_uint8_t etherhdr_size; +- grub_uint16_t vlantag_id = grub_cpu_to_be16_compile_time (VLANTAG_IDENTIFIER); ++ grub_uint32_t vlantag = 0; ++ grub_uint8_t hw_addr_len = inf->card->default_address.len; ++ grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2; + +- etherhdr_size = sizeof (*eth); +- COMPILE_TIME_ASSERT (sizeof (*eth) + 4 < GRUB_NET_MAX_LINK_HEADER_SIZE); ++ /* Source and destination link addresses + ethertype + vlan tag */ ++ COMPILE_TIME_ASSERT ((GRUB_NET_MAX_LINK_ADDRESS_SIZE * 2 + 2 + 4) < ++ GRUB_NET_MAX_LINK_HEADER_SIZE); + + /* Increase ethernet header in case of vlantag */ + if (inf->vlantag != 0) +@@ -70,11 +65,22 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf, + err = grub_netbuff_push (nb, etherhdr_size); + if (err) + return err; +- eth = (struct etherhdr *) nb->data; +- grub_memcpy (eth->dst, target_addr.mac, 6); +- grub_memcpy (eth->src, inf->hwaddress.mac, 6); ++ eth = nb->data; ++ grub_memcpy (eth, target_addr.mac, hw_addr_len); ++ eth += hw_addr_len; ++ grub_memcpy (eth, inf->hwaddress.mac, hw_addr_len); ++ eth += hw_addr_len; ++ ++ /* Check if a vlan-tag is present. */ ++ if (vlantag != 0) ++ { ++ *((grub_uint32_t *)eth) = grub_cpu_to_be32 (vlantag); ++ eth += sizeof (vlantag); ++ } ++ ++ /* Write ethertype */ ++ *((grub_uint16_t*) eth) = grub_cpu_to_be16 (ethertype); + +- eth->type = grub_cpu_to_be16 (ethertype); + if (!inf->card->opened) + { + err = GRUB_ERR_NONE; +@@ -85,19 +91,6 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf, + inf->card->opened = 1; + } + +- /* Check and add a vlan-tag if needed. */ +- if (inf->vlantag != 0) +- { +- /* Move eth type to the right */ +- grub_memcpy ((char *) nb->data + etherhdr_size - 2, +- (char *) nb->data + etherhdr_size - 6, 2); +- +- /* Add the tag in the middle */ +- grub_uint16_t vlan = grub_cpu_to_be16 (inf->vlantag); +- grub_memcpy ((char *) nb->data + etherhdr_size - 6, &vlantag_id, 2); +- grub_memcpy ((char *) nb->data + etherhdr_size - 4, &vlan, 2); +- } +- + return inf->card->driver->send (inf->card, nb); + } + +@@ -105,31 +98,40 @@ grub_err_t + grub_net_recv_ethernet_packet (struct grub_net_buff *nb, + struct grub_net_card *card) + { +- struct etherhdr *eth; ++ grub_uint8_t *eth; + struct llchdr *llch; + struct snaphdr *snaph; + grub_net_ethertype_t type; + grub_net_link_level_address_t hwaddress; + grub_net_link_level_address_t src_hwaddress; + grub_err_t err; +- grub_uint8_t etherhdr_size = sizeof (*eth); ++ grub_uint8_t hw_addr_len = card->default_address.len; ++ grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2; + grub_uint16_t vlantag = 0; + ++ eth = nb->data; + +- /* Check if a vlan-tag is present. If so, the ethernet header is 4 bytes */ +- /* longer than the original one. The vlantag id is extracted and the header */ +- /* is reseted to the original size. */ +- if (grub_get_unaligned16 (nb->data + etherhdr_size - 2) == grub_cpu_to_be16_compile_time (VLANTAG_IDENTIFIER)) ++ hwaddress.type = card->default_address.type; ++ hwaddress.len = hw_addr_len; ++ grub_memcpy (hwaddress.mac, eth, hw_addr_len); ++ eth += hw_addr_len; ++ ++ src_hwaddress.type = card->default_address.type; ++ src_hwaddress.len = hw_addr_len; ++ grub_memcpy (src_hwaddress.mac, eth, hw_addr_len); ++ eth += hw_addr_len; ++ ++ type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth)); ++ if (type == VLANTAG_IDENTIFIER) + { +- vlantag = grub_be_to_cpu16 (grub_get_unaligned16 (nb->data + etherhdr_size)); ++ /* Skip vlan tag */ ++ eth += 2; ++ vlantag = grub_be_to_cpu16 (*(grub_uint16_t*)(eth)); + etherhdr_size += 4; +- /* Move eth type to the original position */ +- grub_memcpy((char *) nb->data + etherhdr_size - 6, +- (char *) nb->data + etherhdr_size - 2, 2); ++ eth += 2; ++ type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth)); + } + +- eth = (struct etherhdr *) nb->data; +- type = grub_be_to_cpu16 (eth->type); + err = grub_netbuff_pull (nb, etherhdr_size); + if (err) + return err; +@@ -149,11 +151,6 @@ grub_net_recv_ethernet_packet (struct grub_net_buff *nb, + } + } + +- hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (hwaddress.mac, eth->dst, sizeof (hwaddress.mac)); +- src_hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (src_hwaddress.mac, eth->src, sizeof (src_hwaddress.mac)); +- + switch (type) + { + /* ARP packet. */ +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index f389bf03d..40df19426 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -26,10 +26,15 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +-#define HTTP_PORT ((grub_uint16_t) 80) ++enum ++ { ++ HTTP_PORT = 80, ++ HTTP_MAX_CHUNK_SIZE = 0x80000000 ++ }; + + typedef struct http_data + { +@@ -82,6 +87,8 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len) + if (data->in_chunk_len == 2) + { + data->chunk_rem = grub_strtoul (ptr, 0, 16); ++ if (data->chunk_rem > HTTP_MAX_CHUNK_SIZE) ++ return GRUB_ERR_NET_PACKET_TOO_BIG; + grub_errno = GRUB_ERR_NONE; + if (data->chunk_rem == 0) + { +@@ -496,13 +503,20 @@ http_open (struct grub_file *file, const char *filename) + { + grub_err_t err; + struct http_data *data; ++ const char *http_path; + + data = grub_zalloc (sizeof (*data)); + if (!data) + return grub_errno; + file->size = GRUB_FILE_SIZE_UNKNOWN; + +- data->filename = grub_strdup (filename); ++ /* If path is relative, prepend http_path */ ++ http_path = grub_env_get ("http_path"); ++ if (http_path && filename[0] != '/') ++ data->filename = grub_xasprintf ("%s/%s", http_path, filename); ++ else ++ data->filename = grub_strdup (filename); ++ + if (!data->filename) + { + grub_free (data); +diff --git a/grub-core/net/icmp6.c b/grub-core/net/icmp6.c +index 9a8c45112..5924fd53a 100644 +--- a/grub-core/net/icmp6.c ++++ b/grub-core/net/icmp6.c +@@ -231,8 +231,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, + && ohdr->len == 1) + { + grub_net_link_level_address_t ll_address; +- ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); ++ ll_address.type = card->default_address.type; ++ ll_address.len = card->default_address.len; ++ grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len); + grub_net_link_layer_add_address (card, source, &ll_address, 0); + } + } +@@ -335,8 +336,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, + && ohdr->len == 1) + { + grub_net_link_level_address_t ll_address; +- ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); ++ ll_address.type = card->default_address.type; ++ ll_address.len = card->default_address.len; ++ grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len); + grub_net_link_layer_add_address (card, source, &ll_address, 0); + } + } +@@ -384,8 +386,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, + && ohdr->len == 1) + { + grub_net_link_level_address_t ll_address; +- ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); ++ ll_address.type = card->default_address.type; ++ ll_address.len = card->default_address.len; ++ grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len); + grub_net_link_layer_add_address (card, source, &ll_address, 0); + } + if (ohdr->type == OPTION_PREFIX && ohdr->len == 4) +diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c +index 3c3d0be0e..3c475762c 100644 +--- a/grub-core/net/ip.c ++++ b/grub-core/net/ip.c +@@ -240,6 +240,45 @@ handle_dgram (struct grub_net_buff *nb, + { + struct udphdr *udph; + udph = (struct udphdr *) nb->data; ++ ++ if (proto == GRUB_NET_IP_UDP && udph->dst == grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT)) ++ { ++ if (udph->chksum) ++ { ++ grub_uint16_t chk, expected; ++ chk = udph->chksum; ++ udph->chksum = 0; ++ expected = grub_net_ip_transport_checksum (nb, ++ GRUB_NET_IP_UDP, ++ source, ++ dest); ++ if (expected != chk) ++ { ++ grub_dprintf ("net", "Invalid UDP checksum. " ++ "Expected %x, got %x\n", ++ grub_be_to_cpu16 (expected), ++ grub_be_to_cpu16 (chk)); ++ grub_netbuff_free (nb); ++ return GRUB_ERR_NONE; ++ } ++ udph->chksum = chk; ++ } ++ ++ err = grub_netbuff_pull (nb, sizeof (*udph)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ err = grub_net_process_dhcp6 (nb, card); ++ if (err) ++ grub_print_error (); ++ ++ grub_netbuff_free (nb); ++ return GRUB_ERR_NONE; ++ } ++ + if (proto == GRUB_NET_IP_UDP && grub_be_to_cpu16 (udph->dst) == 68) + { + const struct grub_net_bootp_packet *bootp; +@@ -277,8 +316,8 @@ handle_dgram (struct grub_net_buff *nb, + if (inf->card == card + && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV + && inf->hwaddress.type == GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET +- && grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr, +- sizeof (inf->hwaddress.mac)) == 0) ++ && (grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr, ++ bootp->hw_len) == 0 || bootp->hw_len == 0)) + { + grub_net_process_dhcp (nb, inf); + grub_netbuff_free (nb); +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 8cad4fb6d..fdec64d55 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -32,6 +32,9 @@ + #include + #include + #include ++#ifdef GRUB_MACHINE_EFI ++#include ++#endif + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -133,8 +136,9 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, + << 48) + && proto_addr->ipv6[1] == (grub_be_to_cpu64_compile_time (1)))) + { +- hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memset (hw_addr->mac, -1, 6); ++ hw_addr->type = inf->card->default_address.type; ++ hw_addr->len = inf->card->default_address.len; ++ grub_memset (hw_addr->mac, -1, hw_addr->len); + return GRUB_ERR_NONE; + } + +@@ -142,6 +146,7 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, + && ((grub_be_to_cpu64 (proto_addr->ipv6[0]) >> 56) == 0xff)) + { + hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ hw_addr->len = inf->card->default_address.len; + hw_addr->mac[0] = 0x33; + hw_addr->mac[1] = 0x33; + hw_addr->mac[2] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 24) & 0xff); +@@ -772,23 +777,23 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf) + void + grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str) + { +- str[0] = 0; +- switch (addr->type) ++ char *ptr; ++ unsigned i; ++ int maxstr; ++ ++ if (addr->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE) + { +- case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET: +- { +- char *ptr; +- unsigned i; +- for (ptr = str, i = 0; i < ARRAY_SIZE (addr->mac); i++) +- { +- grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str), +- "%02x:", addr->mac[i] & 0xff); +- ptr += (sizeof ("XX:") - 1); +- } +- return; +- } ++ str[0] = 0; ++ grub_printf (_("Unsupported hw address type %d len %d\n"), ++ addr->type, addr->len); ++ return; ++ } ++ maxstr = addr->len * grub_strlen ("XX:"); ++ for (ptr = str, i = 0; i < addr->len; i++) ++ { ++ ptr += grub_snprintf (ptr, maxstr - (ptr - str), ++ "%02x:", addr->mac[i] & 0xff); + } +- grub_printf (_("Unsupported hw address type %d\n"), addr->type); + } + + void +@@ -813,13 +818,17 @@ grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a, + return -1; + if (a->type > b->type) + return +1; +- switch (a->type) ++ if (a->len < b->len) ++ return -1; ++ if (a->len > b->len) ++ return +1; ++ if (a->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE) + { +- case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET: +- return grub_memcmp (a->mac, b->mac, sizeof (a->mac)); ++ grub_printf (_("Unsupported hw address type %d len %d\n"), ++ a->type, a->len); ++ return + 1; + } +- grub_printf (_("Unsupported hw address type %d\n"), a->type); +- return 1; ++ return grub_memcmp (a->mac, b->mac, a->len); + } + + int +@@ -984,6 +993,78 @@ grub_net_network_level_interface_register (struct grub_net_network_level_interfa + grub_net_network_level_interfaces = inter; + } + ++int ++grub_ipv6_get_masksize (grub_uint16_t *be_mask) ++{ ++ grub_uint8_t *mask; ++ grub_uint16_t mask16[8]; ++ int x, y; ++ int ret = 128; ++ ++ grub_memcpy (mask16, be_mask, sizeof (mask16)); ++ for (x = 0; x < 8; x++) ++ mask16[x] = grub_be_to_cpu16 (mask16[x]); ++ ++ mask = (grub_uint8_t *)mask16; ++ ++ for (x = 15; x >= 0; x--) ++ { ++ grub_uint8_t octet = mask[x]; ++ if (!octet) ++ { ++ ret -= 8; ++ continue; ++ } ++ for (y = 0; y < 8; y++) ++ { ++ if (octet & (1 << y)) ++ break; ++ else ++ ret--; ++ } ++ break; ++ } ++ ++ return ret; ++} ++ ++grub_err_t ++grub_net_add_ipv6_local (struct grub_net_network_level_interface *inter, ++ int mask) ++{ ++ struct grub_net_route *route; ++ ++ if (inter->address.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6) ++ return 0; ++ ++ if (mask == -1) ++ mask = grub_ipv6_get_masksize ((grub_uint16_t *)inter->address.ipv6); ++ ++ if (mask == -1) ++ return 0; ++ ++ route = grub_zalloc (sizeof (*route)); ++ if (!route) ++ return grub_errno; ++ ++ route->name = grub_xasprintf ("%s:local", inter->name); ++ if (!route->name) ++ { ++ grub_free (route); ++ return grub_errno; ++ } ++ ++ route->target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ grub_memcpy (route->target.ipv6.base, inter->address.ipv6, ++ sizeof (inter->address.ipv6)); ++ route->target.ipv6.masksize = mask; ++ route->is_gateway = 0; ++ route->interface = inter; ++ ++ grub_net_route_register (route); ++ ++ return 0; ++} + + grub_err_t + grub_net_add_ipv4_local (struct grub_net_network_level_interface *inter, +@@ -2005,7 +2086,7 @@ grub_net_search_config_file (char *config) + /* Remove the remaining minus sign at the end. */ + config[config_len] = '\0'; + +- return GRUB_ERR_NONE; ++ return GRUB_ERR_FILE_NOT_FOUND; + } + + static struct grub_preboot *fini_hnd; +@@ -2014,8 +2095,49 @@ static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute; + static grub_command_t cmd_setvlan, cmd_lsroutes, cmd_lscards; + static grub_command_t cmd_lsaddr, cmd_slaac; + ++#ifdef GRUB_MACHINE_EFI ++ ++static enum { ++ INIT_MODE_NONE, ++ INIT_MODE_GRUB, ++ INIT_MODE_EFI ++} init_mode; ++ ++static grub_command_t cmd_bootp, cmd_bootp6; ++ ++#endif ++ + GRUB_MOD_INIT(net) + { ++#ifdef GRUB_MACHINE_EFI ++ if (grub_net_open) ++ return; ++ ++ if ((grub_efi_net_boot_from_https () || grub_efi_net_boot_from_opa ()) ++ && grub_efi_net_fs_init ()) ++ { ++ cmd_lsroutes = grub_register_command ("net_ls_routes", grub_efi_net_list_routes, ++ "", N_("list network routes")); ++ cmd_lscards = grub_register_command ("net_ls_cards", grub_efi_net_list_cards, ++ "", N_("list network cards")); ++ cmd_lsaddr = grub_register_command ("net_ls_addr", grub_efi_net_list_addrs, ++ "", N_("list network addresses")); ++ cmd_addaddr = grub_register_command ("net_add_addr", grub_efi_net_add_addr, ++ /* TRANSLATORS: HWADDRESS stands for ++ "hardware address". */ ++ N_("SHORTNAME CARD ADDRESS [HWADDRESS]"), ++ N_("Add a network address.")); ++ cmd_bootp = grub_register_command ("net_bootp", grub_efi_net_bootp, ++ N_("[CARD]"), ++ N_("perform a bootp autoconfiguration")); ++ cmd_bootp6 = grub_register_command ("net_bootp6", grub_efi_net_bootp6, ++ N_("[CARD]"), ++ N_("perform a bootp autoconfiguration")); ++ init_mode = INIT_MODE_EFI; ++ return; ++ } ++#endif ++ + grub_register_variable_hook ("net_default_server", defserver_get_env, + defserver_set_env); + grub_env_export ("net_default_server"); +@@ -2066,10 +2188,37 @@ GRUB_MOD_INIT(net) + grub_net_restore_hw, + GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK); + grub_net_poll_cards_idle = grub_net_poll_cards_idle_real; ++ ++#ifdef GRUB_MACHINE_EFI ++ grub_env_set ("grub_netfs_type", "grub"); ++ grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly); ++ grub_env_export ("grub_netfs_type"); ++ init_mode = INIT_MODE_GRUB; ++#endif ++ + } + + GRUB_MOD_FINI(net) + { ++ ++#ifdef GRUB_MACHINE_EFI ++ if (init_mode == INIT_MODE_NONE) ++ return; ++ ++ if (init_mode == INIT_MODE_EFI) ++ { ++ grub_unregister_command (cmd_lsroutes); ++ grub_unregister_command (cmd_lscards); ++ grub_unregister_command (cmd_lsaddr); ++ grub_unregister_command (cmd_addaddr); ++ grub_unregister_command (cmd_bootp); ++ grub_unregister_command (cmd_bootp6); ++ grub_efi_net_fs_fini (); ++ init_mode = INIT_MODE_NONE; ++ return; ++ } ++#endif ++ + grub_register_variable_hook ("net_default_server", 0, 0); + grub_register_variable_hook ("pxe_default_server", 0, 0); + +@@ -2088,4 +2237,7 @@ GRUB_MOD_FINI(net) + grub_net_fini_hw (0); + grub_loader_unregister_preboot_hook (fini_hnd); + grub_net_poll_cards_idle = NULL; ++#ifdef GRUB_MACHINE_EFI ++ init_mode = INIT_MODE_NONE; ++#endif + } +diff --git a/grub-core/net/tcp.c b/grub-core/net/tcp.c +index 93dee0caa..902ab7e8a 100644 +--- a/grub-core/net/tcp.c ++++ b/grub-core/net/tcp.c +@@ -106,6 +106,18 @@ struct tcphdr + grub_uint16_t urgent; + } GRUB_PACKED; + ++struct tcp_scale_opt { ++ grub_uint8_t kind; ++ grub_uint8_t length; ++ grub_uint8_t scale; ++} GRUB_PACKED; ++ ++struct tcp_synhdr { ++ struct tcphdr tcphdr; ++ struct tcp_scale_opt scale_opt; ++ grub_uint8_t padding; ++}; ++ + struct tcp_pseudohdr + { + grub_uint32_t src; +@@ -571,7 +583,7 @@ grub_net_tcp_open (char *server, + grub_net_tcp_socket_t socket; + static grub_uint16_t in_port = 21550; + struct grub_net_buff *nb; +- struct tcphdr *tcph; ++ struct tcp_synhdr *tcph; + int i; + grub_uint8_t *nbd; + grub_net_link_level_address_t ll_target_addr; +@@ -640,20 +652,24 @@ grub_net_tcp_open (char *server, + } + + tcph = (void *) nb->data; ++ grub_memset(tcph, 0, sizeof (*tcph)); + socket->my_start_seq = grub_get_time_ms (); + socket->my_cur_seq = socket->my_start_seq + 1; +- socket->my_window = 8192; +- tcph->seqnr = grub_cpu_to_be32 (socket->my_start_seq); +- tcph->ack = grub_cpu_to_be32_compile_time (0); +- tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_SYN); +- tcph->window = grub_cpu_to_be16 (socket->my_window); +- tcph->urgent = 0; +- tcph->src = grub_cpu_to_be16 (socket->in_port); +- tcph->dst = grub_cpu_to_be16 (socket->out_port); +- tcph->checksum = 0; +- tcph->checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP, +- &socket->inf->address, +- &socket->out_nla); ++ socket->my_window = 32768; ++ tcph->tcphdr.seqnr = grub_cpu_to_be32 (socket->my_start_seq); ++ tcph->tcphdr.ack = grub_cpu_to_be32_compile_time (0); ++ tcph->tcphdr.flags = grub_cpu_to_be16_compile_time ((6 << 12) | TCP_SYN); ++ tcph->tcphdr.window = grub_cpu_to_be16 (socket->my_window); ++ tcph->tcphdr.urgent = 0; ++ tcph->tcphdr.src = grub_cpu_to_be16 (socket->in_port); ++ tcph->tcphdr.dst = grub_cpu_to_be16 (socket->out_port); ++ tcph->tcphdr.checksum = 0; ++ tcph->scale_opt.kind = 3; ++ tcph->scale_opt.length = 3; ++ tcph->scale_opt.scale = 5; ++ tcph->tcphdr.checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP, ++ &socket->inf->address, ++ &socket->out_nla); + + tcp_socket_register (socket); + +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index 409b1d09b..f300a9d40 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -359,6 +359,7 @@ tftp_open (struct grub_file *file, const char *filename) + file->not_easily_seekable = 1; + file->data = data; + ++ grub_dprintf("tftp", "resolving address for %s\n", file->device->net->server); + err = grub_net_resolve_address (file->device->net->server, &addr); + if (err) + { +@@ -369,11 +370,13 @@ tftp_open (struct grub_file *file, const char *filename) + return err; + } + ++ grub_dprintf("tftp", "opening connection\n"); + data->sock = grub_net_udp_open (addr, + port ? port : TFTP_SERVER_PORT, tftp_receive, + file); + if (!data->sock) + { ++ grub_dprintf("tftp", "connection failed\n"); + grub_free (data); + return grub_errno; + } +diff --git a/grub-core/normal/context.c b/grub-core/normal/context.c +index ba185e915..b4baa4392 100644 +--- a/grub-core/normal/context.c ++++ b/grub-core/normal/context.c +@@ -99,7 +99,7 @@ grub_env_new_context (int export_all) + grub_err_t + grub_env_context_open (void) + { +- return grub_env_new_context (0); ++ return grub_env_new_context (1); + } + + int grub_extractor_level = 0; +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index bd4431000..26872ce94 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -34,6 +35,9 @@ + #include + #include + #include ++#ifdef GRUB_MACHINE_IEEE1275 ++#include ++#endif + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -67,6 +71,11 @@ grub_normal_free_menu (grub_menu_t menu) + grub_free (entry->args); + } + ++ if (entry->bls) ++ { ++ entry->bls->visible = 0; ++ } ++ + grub_free ((void *) entry->id); + grub_free ((void *) entry->users); + grub_free ((void *) entry->title); +@@ -207,9 +216,10 @@ grub_normal_init_page (struct grub_term_output *term, + grub_uint32_t *unicode_msg; + grub_uint32_t *last_position; + +- grub_term_cls (term); ++ if (! grub_debug_is_enabled ()) ++ grub_term_cls (term); + +- msg_formatted = grub_xasprintf (_("GNU GRUB version %s"), PACKAGE_VERSION); ++ msg_formatted = grub_xasprintf (_("GRUB version %s"), PACKAGE_VERSION); + if (!msg_formatted) + return; + +@@ -276,6 +286,22 @@ grub_normal_execute (const char *config, int nested, int batch) + { + menu = read_config_file (config); + ++#ifdef GRUB_MACHINE_IEEE1275 ++ int boot; ++ boot = 0; ++ char *script; ++ script = grub_malloc (1024); ++ if (! grub_ieee1275_cas_reboot (script)) ++ { ++ char *dummy[1] = { NULL }; ++ if (! grub_script_execute_sourcecode (script)) ++ boot = 1; ++ } ++ grub_free (script); ++ if (boot) ++ grub_command_execute ("boot", 0, 0); ++#endif ++ + /* Ignore any error. */ + grub_errno = GRUB_ERR_NONE; + } +@@ -310,52 +336,127 @@ grub_enter_normal_mode (const char *config) + grub_boot_time ("Exiting normal mode"); + } + +-/* Enter normal mode from rescue mode. */ + static grub_err_t +-grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), +- int argc, char *argv[]) ++grub_try_normal_prefix (const char *prefix) + { +- if (argc == 0) +- { +- /* Guess the config filename. It is necessary to make CONFIG static, +- so that it won't get broken by longjmp. */ +- char *config; +- const char *prefix; ++ char *config; ++ grub_err_t err = GRUB_ERR_FILE_NOT_FOUND; ++ const char *net_search_cfg; ++ int disable_net_search = 0; ++ ++ net_search_cfg = grub_env_get ("feature_net_search_cfg"); ++ if (net_search_cfg && net_search_cfg[0] == 'n') ++ disable_net_search = 1; ++ ++ if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0 && ++ !disable_net_search) ++ { ++ grub_size_t config_len; ++ config_len = grub_strlen (prefix) + ++ sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"); ++ config = grub_malloc (config_len); ++ ++ if (! config) ++ return err; ++ ++ grub_snprintf (config, config_len, "%s/grub.cfg", prefix); ++ err = grub_net_search_config_file (config); ++ } ++ ++ if (err != GRUB_ERR_NONE) ++ { ++ config = grub_xasprintf ("%s/grub.cfg", prefix); ++ if (config) ++ { ++ grub_file_t file; ++ file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG); ++ if (file) ++ { ++ grub_file_close (file); ++ err = GRUB_ERR_NONE; ++ } ++ } ++ } ++ ++ if (err == GRUB_ERR_NONE) ++ grub_enter_normal_mode (config); ++ ++ grub_errno = 0; ++ grub_free (config); ++ return err; ++} + +- prefix = grub_env_get ("prefix"); +- if (prefix) +- { +- grub_size_t config_len; +- int disable_net_search = 0; +- const char *net_search_cfg; ++static int ++grub_try_normal_dev (const char *name, void *data) ++{ ++ grub_err_t err; ++ const char *prefix = grub_xasprintf ("(%s)%s", name, (char *)data); + +- config_len = grub_strlen (prefix) + +- sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"); +- config = grub_malloc (config_len); ++ if (!prefix) ++ return 0; + +- if (!config) +- goto quit; ++ err = grub_try_normal_prefix (prefix); ++ if (err == GRUB_ERR_NONE) ++ return 1; + +- grub_snprintf (config, config_len, "%s/grub.cfg", prefix); ++ return 0; ++} + +- net_search_cfg = grub_env_get ("feature_net_search_cfg"); +- if (net_search_cfg && net_search_cfg[0] == 'n') +- disable_net_search = 1; ++static grub_err_t ++grub_try_normal_discover (void) ++{ ++ const char *prefix = grub_env_get ("prefix"); ++ grub_err_t err = GRUB_ERR_FILE_NOT_FOUND; + +- if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0 && +- !disable_net_search) +- grub_net_search_config_file (config); ++ if (!prefix) ++ return err; + +- grub_enter_normal_mode (config); +- grub_free (config); +- } +- else +- grub_enter_normal_mode (0); +- } +- else ++ if (grub_device_iterate (grub_try_normal_dev, (void *)prefix)) ++ return GRUB_ERR_NONE; ++ ++ return err; ++} ++ ++static grub_err_t ++grub_try_normal (const char *variable) ++{ ++ grub_err_t err = GRUB_ERR_FILE_NOT_FOUND; ++ const char *prefix; ++ ++ if (!variable) ++ return err; ++ ++ prefix = grub_env_get (variable); ++ if (!prefix) ++ return err; ++ ++ return grub_try_normal_prefix (prefix); ++} ++ ++/* Enter normal mode from rescue mode. */ ++static grub_err_t ++grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ if (argc) + grub_enter_normal_mode (argv[0]); ++ else ++ { ++ /* Guess the config filename. */ ++ grub_err_t err; ++ err = grub_try_normal ("fw_path"); ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ err = grub_try_normal ("prefix"); ++#ifdef __powerpc__ ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ err = grub_try_normal_prefix ("/boot/grub"); ++#endif ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ err = grub_try_normal_discover (); ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ grub_enter_normal_mode (0); ++ } + +-quit: + return 0; + } + +@@ -378,6 +479,9 @@ grub_normal_reader_init (int nested) + const char *msg_esc = _("ESC at any time exits."); + char *msg_formatted; + ++ if (grub_env_get ("debug") != NULL) ++ return 0; ++ + msg_formatted = grub_xasprintf (_("Minimal BASH-like line editing is supported. For " + "the first word, TAB lists possible command completions. Anywhere " + "else TAB lists possible device or file completions. To enable " +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index 6a90e091f..cda10fa8b 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -163,12 +163,92 @@ grub_menu_set_timeout (int timeout) + } + } + ++static int ++menuentry_eq (const char *id, const char *spec, int limit) ++{ ++ const char *ptr1, *ptr2; ++ ptr1 = id; ++ ptr2 = spec; ++ while (limit == -1 || ptr1 - id <= limit) ++ { ++ if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0) ++ return ptr2 - spec; ++ if (*ptr2 == '>' && ptr2[1] != '>') ++ return 0; ++ if (*ptr2 == '>') ++ ptr2++; ++ if (*ptr1 != *ptr2) ++ { ++ if (limit > -1 && ptr1 - id == limit && !*ptr1 && grub_isspace(*ptr2)) ++ return ptr1 -id -1; ++ return 0; ++ } ++ if (*ptr1 == 0) ++ return ptr1 - id; ++ ptr1++; ++ ptr2++; ++ } ++ return 0; ++} ++ ++static int ++get_entry_number_helper(grub_menu_t menu, ++ const char * const val, const char ** const tail) ++{ ++ /* See if the variable matches the title of a menu entry. */ ++ int entry = -1; ++ grub_menu_entry_t e; ++ int i; ++ ++ for (i = 0, e = menu->entry_list; e; i++) ++ { ++ int l = 0; ++ while (val[l] && !grub_isspace(val[l])) ++ l++; ++ ++ if (menuentry_eq (e->id, val, l)) ++ { ++ if (tail) ++ *tail = val + l; ++ return i; ++ } ++ e = e->next; ++ } ++ ++ for (i = 0, e = menu->entry_list; e; i++) ++ { ++ ++ if (menuentry_eq (e->title, val, -1)) ++ { ++ if (tail) ++ *tail = NULL; ++ return i; ++ } ++ e = e->next; ++ } ++ ++ if (tail) ++ *tail = NULL; ++ ++ entry = (int) grub_strtoul (val, tail, 0); ++ if (grub_errno == GRUB_ERR_BAD_NUMBER || ++ (*tail && **tail && !grub_isspace(**tail))) ++ { ++ entry = -1; ++ if (tail) ++ *tail = NULL; ++ grub_errno = GRUB_ERR_NONE; ++ } ++ ++ return entry; ++} ++ + /* Get the first entry number from the value of the environment variable NAME, + which is a space-separated list of non-negative integers. The entry number + which is returned is stripped from the value of NAME. If no entry number + can be found, -1 is returned. */ + static int +-get_and_remove_first_entry_number (const char *name) ++get_and_remove_first_entry_number (grub_menu_t menu, const char *name) + { + const char *val, *tail; + int entry; +@@ -179,20 +259,24 @@ get_and_remove_first_entry_number (const char *name) + + grub_error_push (); + +- entry = (int) grub_strtoul (val, &tail, 0); ++ entry = get_entry_number_helper(menu, val, &tail); ++ if (!(*tail == 0 || grub_isspace(*tail))) ++ entry = -1; + +- if (grub_errno == GRUB_ERR_NONE) ++ if (entry >= 0) + { +- /* Skip whitespace to find the next digit. */ ++ /* Skip whitespace to find the next entry. */ + while (*tail && grub_isspace (*tail)) + tail++; +- grub_env_set (name, tail); ++ if (*tail) ++ grub_env_set (name, tail); ++ else ++ grub_env_unset (name); + } + else + { + grub_env_unset (name); + grub_errno = GRUB_ERR_NONE; +- entry = -1; + } + + grub_error_pop (); +@@ -201,7 +285,7 @@ get_and_remove_first_entry_number (const char *name) + } + + /* Run a menu entry. */ +-static void ++static grub_err_t + grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + { + grub_err_t err = GRUB_ERR_NONE; +@@ -218,7 +302,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; +- return; ++ return grub_errno; + } + + errs_before = grub_err_printed_errors; +@@ -231,7 +315,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + grub_env_context_open (); + menu = grub_zalloc (sizeof (*menu)); + if (! menu) +- return; ++ return grub_errno; + grub_env_set_menu (menu); + if (auto_boot) + grub_env_set ("timeout", "0"); +@@ -291,8 +375,6 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + + if (ptr && ptr[0] && ptr[1]) + grub_env_set ("default", ptr + 1); +- else +- grub_env_unset ("default"); + + grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args); + +@@ -303,7 +385,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + + if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) + /* Implicit execution of boot, only if something is loaded. */ +- grub_command_execute ("boot", 0, 0); ++ err = grub_command_execute ("boot", 0, 0); + + if (errs_before != grub_err_printed_errors) + grub_wait_after_message (); +@@ -326,6 +408,8 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + else + grub_env_unset ("default"); + grub_env_unset ("timeout"); ++ ++ return err; + } + + /* Execute ENTRY from the menu MENU, falling back to entries specified +@@ -340,13 +424,16 @@ grub_menu_execute_with_fallback (grub_menu_t menu, + void *callback_data) + { + int fallback_entry; ++ grub_err_t err; + + callback->notify_booting (entry, callback_data); + +- grub_menu_execute_entry (entry, 1); ++ err = grub_menu_execute_entry (entry, 1); ++ if (err == GRUB_ERR_NONE) ++ return; + + /* Deal with fallback entries. */ +- while ((fallback_entry = get_and_remove_first_entry_number ("fallback")) ++ while ((fallback_entry = get_and_remove_first_entry_number (menu, "fallback")) + >= 0) + { + grub_print_error (); +@@ -354,11 +441,9 @@ grub_menu_execute_with_fallback (grub_menu_t menu, + + entry = grub_menu_get_entry (menu, fallback_entry); + callback->notify_fallback (entry, callback_data); +- grub_menu_execute_entry (entry, 1); +- /* If the function call to execute the entry returns at all, then this is +- taken to indicate a boot failure. For menu entries that do something +- other than actually boot an operating system, this could assume +- incorrectly that something failed. */ ++ err = grub_menu_execute_entry (entry, 1); ++ if (err == GRUB_ERR_NONE) ++ return; + } + + if (!autobooted) +@@ -464,35 +549,12 @@ grub_menu_register_viewer (struct grub_menu_viewer *viewer) + viewers = viewer; + } + +-static int +-menuentry_eq (const char *id, const char *spec) +-{ +- const char *ptr1, *ptr2; +- ptr1 = id; +- ptr2 = spec; +- while (1) +- { +- if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0) +- return 1; +- if (*ptr2 == '>' && ptr2[1] != '>') +- return 0; +- if (*ptr2 == '>') +- ptr2++; +- if (*ptr1 != *ptr2) +- return 0; +- if (*ptr1 == 0) +- return 1; +- ptr1++; +- ptr2++; +- } +-} +- +- + /* Get the entry number from the variable NAME. */ + static int + get_entry_number (grub_menu_t menu, const char *name) + { + const char *val; ++ const char *tail; + int entry; + + val = grub_env_get (name); +@@ -500,38 +562,9 @@ get_entry_number (grub_menu_t menu, const char *name) + return -1; + + grub_error_push (); +- +- entry = (int) grub_strtoul (val, 0, 0); +- +- if (grub_errno == GRUB_ERR_BAD_NUMBER) +- { +- /* See if the variable matches the title of a menu entry. */ +- grub_menu_entry_t e = menu->entry_list; +- int i; +- +- grub_errno = GRUB_ERR_NONE; +- +- for (i = 0; e; i++) +- { +- if (menuentry_eq (e->title, val) +- || menuentry_eq (e->id, val)) +- { +- entry = i; +- break; +- } +- e = e->next; +- } +- +- if (! e) +- entry = -1; +- } +- +- if (grub_errno != GRUB_ERR_NONE) +- { +- grub_errno = GRUB_ERR_NONE; +- entry = -1; +- } +- ++ entry = get_entry_number_helper(menu, val, &tail); ++ if (tail && *tail != '\0') ++ entry = -1; + grub_error_pop (); + + return entry; +diff --git a/grub-core/osdep/linux/blocklist.c b/grub-core/osdep/linux/blocklist.c +index 2efee2c2a..902cfee53 100644 +--- a/grub-core/osdep/linux/blocklist.c ++++ b/grub-core/osdep/linux/blocklist.c +@@ -109,7 +109,7 @@ grub_install_get_blocklist (grub_device_t root_dev, + else + { + struct fiemap *fie2; +- int i; ++ unsigned int i; + fie2 = xmalloc (sizeof (*fie2) + + fie1.fm_mapped_extents + * sizeof (fie1.fm_extents[1])); +diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c +index 7dd775d2a..b32582eb3 100644 +--- a/grub-core/osdep/linux/getroot.c ++++ b/grub-core/osdep/linux/getroot.c +@@ -103,6 +103,14 @@ struct btrfs_ioctl_search_key + grub_uint32_t unused[9]; + }; + ++struct btrfs_ioctl_search_header { ++ grub_uint64_t transid; ++ grub_uint64_t objectid; ++ grub_uint64_t offset; ++ grub_uint32_t type; ++ grub_uint32_t len; ++}; ++ + struct btrfs_ioctl_search_args { + struct btrfs_ioctl_search_key key; + grub_uint64_t buf[(4096 - sizeof(struct btrfs_ioctl_search_key)) +@@ -225,7 +233,7 @@ grub_find_root_devices_from_btrfs (const char *dir) + { + int fd; + struct btrfs_ioctl_fs_info_args fsi; +- int i, j = 0; ++ unsigned int i, j = 0; + char **ret; + + fd = open (dir, 0); +@@ -373,6 +381,110 @@ get_btrfs_fs_prefix (const char *mount_path) + return NULL; + } + ++int use_relative_path_on_btrfs = 0; ++ ++static char * ++get_btrfs_subvol (const char *path) ++{ ++ struct btrfs_ioctl_ino_lookup_args args; ++ grub_uint64_t tree_id; ++ int fd = -1; ++ char *ret = NULL; ++ ++ fd = open (path, O_RDONLY); ++ ++ if (fd < 0) ++ return NULL; ++ ++ memset (&args, 0, sizeof(args)); ++ args.objectid = GRUB_BTRFS_TREE_ROOT_OBJECTID; ++ ++ if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0) ++ goto error; ++ ++ tree_id = args.treeid; ++ ++ while (tree_id != GRUB_BTRFS_ROOT_VOL_OBJECTID) ++ { ++ struct btrfs_ioctl_search_args sargs; ++ struct grub_btrfs_root_backref *br; ++ struct btrfs_ioctl_search_header *search_header; ++ char *old; ++ grub_uint16_t len; ++ grub_uint64_t inode_id; ++ ++ memset (&sargs, 0, sizeof(sargs)); ++ ++ sargs.key.tree_id = 1; ++ sargs.key.min_objectid = tree_id; ++ sargs.key.max_objectid = tree_id; ++ ++ sargs.key.min_offset = 0; ++ sargs.key.max_offset = ~0ULL; ++ sargs.key.min_transid = 0; ++ sargs.key.max_transid = ~0ULL; ++ sargs.key.min_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF; ++ sargs.key.max_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF; ++ ++ sargs.key.nr_items = 1; ++ ++ if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0) ++ goto error; ++ ++ if (sargs.key.nr_items == 0) ++ goto error; ++ ++ search_header = (struct btrfs_ioctl_search_header *)sargs.buf; ++ br = (struct grub_btrfs_root_backref *) (search_header + 1); ++ ++ len = grub_le_to_cpu16 (br->n); ++ inode_id = grub_le_to_cpu64 (br->inode_id); ++ tree_id = search_header->offset; ++ ++ old = ret; ++ ret = malloc (len + 1); ++ memcpy (ret, br->name, len); ++ ret[len] = '\0'; ++ ++ if (inode_id != GRUB_BTRFS_TREE_ROOT_OBJECTID) ++ { ++ char *s; ++ ++ memset(&args, 0, sizeof(args)); ++ args.treeid = search_header->offset; ++ args.objectid = inode_id; ++ ++ if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0) ++ goto error; ++ ++ s = xasprintf ("%s%s", args.name, ret); ++ free (ret); ++ ret = s; ++ } ++ ++ if (old) ++ { ++ char *s = xasprintf ("%s/%s", ret, old); ++ free (ret); ++ free (old); ++ ret = s; ++ } ++ } ++ ++ close (fd); ++ return ret; ++ ++error: ++ ++ if (fd >= 0) ++ close (fd); ++ if (ret) ++ free (ret); ++ ++ return NULL; ++} ++ ++void (*grub_find_root_btrfs_mount_path_hook)(const char *mount_path); + + char ** + grub_find_root_devices_from_mountinfo (const char *dir, char **relroot) +@@ -515,7 +627,16 @@ again: + else if (grub_strcmp (entries[i].fstype, "btrfs") == 0) + { + ret = grub_find_root_devices_from_btrfs (dir); +- fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); ++ if (use_relative_path_on_btrfs) ++ { ++ fs_prefix = xstrdup ("/"); ++ if (grub_find_root_btrfs_mount_path_hook) ++ grub_find_root_btrfs_mount_path_hook (entries[i].enc_path); ++ } ++ else ++ { ++ fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); ++ } + } + else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0) + { +@@ -1140,6 +1261,32 @@ grub_util_get_grub_dev_os (const char *os_dev) + return grub_dev; + } + ++static void *mp = NULL; ++static void ++btrfs_mount_path_hook(const char *m) ++{ ++ mp = strdup (m); ++} ++ ++char * ++grub_util_get_btrfs_subvol (const char *path, char **mount_path) ++{ ++ if (mount_path) ++ *mount_path = NULL; ++ ++ grub_find_root_btrfs_mount_path_hook = btrfs_mount_path_hook; ++ grub_free (grub_find_root_devices_from_mountinfo (path, NULL)); ++ grub_find_root_btrfs_mount_path_hook = NULL; ++ ++ if (!mp) ++ return NULL; ++ ++ if (mount_path) ++ *mount_path = mp; ++ ++ return get_btrfs_subvol (mp); ++} ++ + char * + grub_make_system_path_relative_to_its_root_os (const char *path) + { +diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c +index a6153d359..72772c87a 100644 +--- a/grub-core/osdep/linux/ofpath.c ++++ b/grub-core/osdep/linux/ofpath.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + #ifdef __sparc__ + typedef enum +@@ -350,6 +351,38 @@ of_path_of_ide(const char *sys_devname __attribute__((unused)), const char *devi + return ret; + } + ++ ++static void ++of_fc_port_name(const char *path, const char *subpath, char *port_name) ++{ ++ char *bname, *basepath, *p; ++ int fd; ++ ++ bname = xmalloc(sizeof(char)*150); ++ basepath = xmalloc(strlen(path)); ++ ++ /* Generate the path to get port name information from the drive */ ++ strncpy(basepath,path,subpath-path); ++ basepath[subpath-path-1] = '\0'; ++ p = get_basename(basepath); ++ snprintf(bname,sizeof(char)*150,"%s/fc_transport/%s/port_name",basepath,p); ++ ++ /* Read the information from the port name */ ++ fd = open (bname, O_RDONLY); ++ if (fd < 0) ++ grub_util_error (_("cannot open `%s': %s"), bname, strerror (errno)); ++ ++ if (read(fd,port_name,sizeof(char)*19) < 0) ++ grub_util_error (_("cannot read `%s': %s"), bname, strerror (errno)); ++ ++ sscanf(port_name,"0x%s",port_name); ++ ++ close(fd); ++ ++ free(bname); ++ free(basepath); ++} ++ + #ifdef __sparc__ + static char * + of_path_of_nvme(const char *sys_devname __attribute__((unused)), +@@ -577,6 +610,16 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev + digit_string = trailing_digits (device); + if (strncmp (of_path, "/vdevice/", sizeof ("/vdevice/") - 1) == 0) + { ++ if(strstr(of_path,"vfc-client")) ++ { ++ char * port_name = xmalloc(sizeof(char)*17); ++ of_fc_port_name(sysfs_path, p, port_name); ++ ++ snprintf(disk,sizeof(disk),"/%s@%s", disk_name, port_name); ++ free(port_name); ++ } ++ else ++ { + unsigned long id = 0x8000 | (tgt << 8) | (bus << 5) | lun; + if (*digit_string == '\0') + { +@@ -590,6 +633,13 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev + snprintf(disk, sizeof (disk), + "/%s@%04lx000000000000:%c", disk_name, id, 'a' + (part - 1)); + } ++ } ++ } else if (strstr(of_path,"fibre-channel")||(strstr(of_path,"vfc-client"))){ ++ char * port_name = xmalloc(sizeof(char)*17); ++ of_fc_port_name(sysfs_path, p, port_name); ++ ++ snprintf(disk,sizeof(disk),"/%s@%s", disk_name, port_name); ++ free(port_name); + } + else + { +@@ -706,13 +756,74 @@ strip_trailing_digits (const char *p) + return new; + } + ++static char * ++get_slave_from_dm(const char * device){ ++ char *curr_device, *tmp; ++ char *directory; ++ char *ret = NULL; ++ ++ directory = grub_strdup (device); ++ tmp = get_basename(directory); ++ curr_device = grub_strdup (tmp); ++ *tmp = '\0'; ++ ++ /* Recursively check for slaves devices so we can find the root device */ ++ while ((curr_device[0] == 'd') && (curr_device[1] == 'm') && (curr_device[2] == '-')){ ++ DIR *dp; ++ struct dirent *ep; ++ char* device_path; ++ ++ device_path = grub_xasprintf ("/sys/block/%s/slaves", curr_device); ++ dp = opendir(device_path); ++ if (dp == NULL) ++ grub_util_warn (_("cannot open directory `%s'"), device_path); ++ free(device_path); ++ ++ if (dp != NULL) ++ { ++ ep = readdir (dp); ++ while (ep != NULL){ ++ ++ /* avoid some system directories */ ++ if (!strcmp(ep->d_name,".")) ++ goto next_dir; ++ if (!strcmp(ep->d_name,"..")) ++ goto next_dir; ++ ++ free (curr_device); ++ free (ret); ++ curr_device = grub_strdup (ep->d_name); ++ ret = grub_xasprintf ("%s%s", directory, curr_device); ++ break; ++ ++ next_dir: ++ ep = readdir (dp); ++ continue; ++ } ++ closedir (dp); ++ } ++ } ++ ++ free (directory); ++ free (curr_device); ++ ++ return ret; ++} ++ + char * + grub_util_devname_to_ofpath (const char *sys_devname) + { +- char *name_buf, *device, *devnode, *devicenode, *ofpath; ++ char *name_buf, *device, *devnode, *devicenode, *ofpath, *realname; + + name_buf = xrealpath (sys_devname); + ++ realname = get_slave_from_dm (name_buf); ++ if (realname) ++ { ++ free (name_buf); ++ name_buf = realname; ++ } ++ + device = get_basename (name_buf); + devnode = strip_trailing_digits (name_buf); + devicenode = strip_trailing_digits (device); +diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c +index 0b1f7618d..0ce0e309a 100644 +--- a/grub-core/osdep/unix/config.c ++++ b/grub-core/osdep/unix/config.c +@@ -82,6 +82,19 @@ grub_util_load_config (struct grub_util_config *cfg) + if (v) + cfg->grub_distributor = xstrdup (v); + ++ v = getenv ("SUSE_BTRFS_SNAPSHOT_BOOTING"); ++ if (v) ++ { ++ if (grub_strncmp(v, "true", sizeof ("true") - 1) == 0) ++ { ++ cfg->is_suse_btrfs_snapshot_enabled = 1; ++ } ++ else ++ { ++ cfg->is_suse_btrfs_snapshot_enabled = 0; ++ } ++ } ++ + cfgfile = grub_util_get_config_filename (); + if (!grub_util_is_regular (cfgfile)) + return; +@@ -105,8 +118,8 @@ grub_util_load_config (struct grub_util_config *cfg) + *ptr++ = *iptr; + } + +- strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" " +- "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\""); ++ strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\nSUSE_BTRFS_SNAPSHOT_BOOTING=%s\\n\" " ++ "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\" \"$SUSE_BTRFS_SNAPSHOT_BOOTING\""); + + argv[2] = script; + argv[3] = '\0'; +diff --git a/grub-core/osdep/unix/hostdisk.c b/grub-core/osdep/unix/hostdisk.c +index 3a00d7451..e5f4b4d5f 100644 +--- a/grub-core/osdep/unix/hostdisk.c ++++ b/grub-core/osdep/unix/hostdisk.c +@@ -71,6 +71,12 @@ grub_util_get_fd_size (grub_util_fd_t fd, const char *name, unsigned *log_secsiz + if (log_secsize) + *log_secsize = 9; + ++#ifdef GRUB_MACHINE_EMU ++ /* /proc doesn't behave itself and gives 0 for file sizes to stat. */ ++ if (st.st_size == 0 && !grub_strncmp ("/proc", name, 5)) ++ return -1; ++#endif ++ + return st.st_size; + } + +diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c +index 14ff09094..c19b4bf70 100644 +--- a/grub-core/script/execute.c ++++ b/grub-core/script/execute.c +@@ -28,6 +28,9 @@ + #include + #include + #include ++#ifdef GRUB_MACHINE_IEEE1275 ++#include ++#endif + + /* Max digits for a char is 3 (0xFF is 255), similarly for an int it + is sizeof (int) * 3, and one extra for a possible -ve sign. */ +@@ -53,6 +56,12 @@ static struct grub_script_scope *scope = 0; + /* Wildcard translator for GRUB script. */ + struct grub_script_wildcard_translator *grub_wildcard_translator; + ++static int ++is_hex(char c) ++{ ++ return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); ++} ++ + static char* + wildcard_escape (const char *s) + { +@@ -69,7 +78,15 @@ wildcard_escape (const char *s) + i = 0; + while ((ch = *s++)) + { +- if (ch == '*' || ch == '\\' || ch == '?') ++ if (ch == '\\' && s[0] == 'x' && is_hex(s[1]) && is_hex(s[2])) ++ { ++ p[i++] = ch; ++ p[i++] = *s++; ++ p[i++] = *s++; ++ p[i++] = *s++; ++ continue; ++ } ++ else if (ch == '*' || ch == '\\' || ch == '?') + p[i++] = '\\'; + p[i++] = ch; + } +@@ -93,7 +110,14 @@ wildcard_unescape (const char *s) + i = 0; + while ((ch = *s++)) + { +- if (ch == '\\') ++ if (ch == '\\' && s[0] == 'x' && is_hex(s[1]) && is_hex(s[2])) ++ { ++ p[i++] = '\\'; ++ p[i++] = *s++; ++ p[i++] = *s++; ++ p[i++] = *s++; ++ } ++ else if (ch == '\\') + p[i++] = *s++; + else + p[i++] = ch; +@@ -395,10 +419,20 @@ parse_string (const char *str, + switch (*ptr) + { + case '\\': +- escaped = !escaped; +- if (!escaped && put) +- *(put++) = '\\'; +- ptr++; ++ if (!escaped && put && *(ptr+1) == 'x' && is_hex(*(ptr+2)) && is_hex(*(ptr+3))) ++ { ++ *(put++) = *ptr++; ++ *(put++) = *ptr++; ++ *(put++) = *ptr++; ++ *(put++) = *ptr++; ++ } ++ else ++ { ++ escaped = !escaped; ++ if (!escaped && put) ++ *(put++) = '\\'; ++ ptr++; ++ } + break; + case '$': + if (escaped) +@@ -883,6 +917,10 @@ grub_script_execute_sourcecode (const char *source) + grub_err_t ret = 0; + struct grub_script *parsed_script; + ++#ifdef GRUB_MACHINE_IEEE1275 ++ grub_ieee1275_set_boot_last_label (source); ++#endif ++ + while (source) + { + char *line; +diff --git a/grub-core/script/script.c b/grub-core/script/script.c +index ec4d4337c..844e8343c 100644 +--- a/grub-core/script/script.c ++++ b/grub-core/script/script.c +@@ -22,6 +22,11 @@ + #include + #include + ++#ifdef grub_dprintf ++#undef grub_dprintf ++#endif ++#define grub_dprintf(no, fmt, ...) ++ + /* It is not possible to deallocate the memory when a syntax error was + found. Because of that it is required to keep track of all memory + allocations. The memory is freed in case of an error, or assigned +diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c +index f8a129eb7..d2b716b5b 100644 +--- a/grub-core/term/at_keyboard.c ++++ b/grub-core/term/at_keyboard.c +@@ -25,12 +25,14 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_uint8_t grub_keyboard_controller_orig; + static grub_uint8_t grub_keyboard_orig_set; + struct grub_ps2_state ps2_state; ++static int fallback_set; + + static int ping_sent; + +@@ -86,10 +88,12 @@ at_command (grub_uint8_t data) + break; + return 0; + } ++ if (i == GRUB_AT_TRIES) ++ grub_dprintf ("atkeyb", "at_command() timed out! (stopped after %d tries)\n", i); + return (i != GRUB_AT_TRIES); + } + +-static void ++static void __attribute__((__unused__)) + grub_keyboard_controller_write (grub_uint8_t c) + { + at_command (KEYBOARD_COMMAND_WRITE); +@@ -115,6 +119,21 @@ grub_keyboard_controller_read (void) + + #endif + ++static int ++resend_last_result (void) ++{ ++ grub_uint8_t ret; ++ keyboard_controller_wait_until_ready (); ++ grub_dprintf ("atkeyb", "resend_last_result: sending 0xfe\n"); ++ grub_outb (0xfe, KEYBOARD_REG_DATA); ++ ret = wait_ack (); ++ grub_dprintf ("atkeyb", "resend_last_result: wait_ack() returned 0x%x\n", ret); ++ keyboard_controller_wait_until_ready (); ++ ret = grub_inb (KEYBOARD_REG_DATA); ++ grub_dprintf ("atkeyb", "resend_last_result: read 0x%x from controller\n", ret); ++ return ret; ++} ++ + static int + write_mode (int mode) + { +@@ -123,11 +142,14 @@ write_mode (int mode) + { + grub_uint8_t ack; + keyboard_controller_wait_until_ready (); ++ grub_dprintf ("atkeyb", "write_mode: sending 0xf0\n"); + grub_outb (0xf0, KEYBOARD_REG_DATA); + keyboard_controller_wait_until_ready (); ++ grub_dprintf ("atkeyb", "write_mode: sending mode %d\n", mode); + grub_outb (mode, KEYBOARD_REG_DATA); + keyboard_controller_wait_until_ready (); + ack = wait_ack (); ++ grub_dprintf ("atkeyb", "write_mode: wait_ack() returned 0x%x\n", ack); + if (ack == GRUB_AT_NACK) + continue; + if (ack == GRUB_AT_ACK) +@@ -135,6 +157,9 @@ write_mode (int mode) + return 0; + } + ++ if (i == GRUB_AT_TRIES) ++ grub_dprintf ("atkeyb", "write_mode() timed out! (stopped after %d tries)\n", i); ++ + return (i != GRUB_AT_TRIES); + } + +@@ -142,23 +167,66 @@ static int + query_mode (void) + { + grub_uint8_t ret; ++ grub_uint64_t endtime; ++ unsigned i; + int e; ++ const char *envvar; + +- e = write_mode (0); +- if (!e) +- return 0; ++ for (i = 0; i < GRUB_AT_TRIES; i++) { ++ grub_dprintf ("atkeyb", "query_mode: sending command to controller\n"); ++ e = write_mode (0); ++ if (!e) { ++ grub_dprintf ("atkeyb", "query_mode: write_mode(0) failed\n"); ++ return 0; ++ } + +- do { +- keyboard_controller_wait_until_ready (); +- ret = grub_inb (KEYBOARD_REG_DATA); +- } while (ret == GRUB_AT_ACK); +- /* QEMU translates the set even in no-translate mode. */ +- if (ret == 0x43 || ret == 1) +- return 1; +- if (ret == 0x41 || ret == 2) +- return 2; +- if (ret == 0x3f || ret == 3) +- return 3; ++ endtime = grub_get_time_ms () + 20; ++ do { ++ keyboard_controller_wait_until_ready (); ++ ret = grub_inb (KEYBOARD_REG_DATA); ++ grub_dprintf ("atkeyb", "query_mode/loop: read 0x%x from controller\n", ret); ++ } while ((ret == GRUB_AT_ACK || ret == GRUB_AT_NACK) && grub_get_time_ms () < endtime); ++ if (ret == 0xfe) { ++ grub_dprintf ("atkeyb", "query_mode: asking controller to resend last result\n"); ++ ret = resend_last_result(); ++ grub_dprintf ("atkeyb", "query_mode: read 0x%x from controller\n", ret); ++ } ++ /* QEMU translates the set even in no-translate mode. */ ++ if (ret == 0x43 || ret == 1) { ++ grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 1\n", ret); ++ return 1; ++ } ++ if (ret == 0x41 || ret == 2) { ++ grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 2\n", ret); ++ return 2; ++ } ++ if (ret == 0x3f || ret == 3) { ++ grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 3\n", ret); ++ return 3; ++ } ++ grub_dprintf ("atkeyb", "query_mode: controller returned unexpected value 0x%x, retrying\n", ret); ++ } ++ ++ /* ++ * Falling here means we tried querying and the controller returned something ++ * we don't understand, try to use 'at_keyboard_fallback_set' if it exists, ++ * otherwise return 0. ++ */ ++ envvar = grub_env_get ("at_keyboard_fallback_set"); ++ if (envvar) { ++ fallback_set = grub_strtoul (envvar, 0, 10); ++ if ((grub_errno) || (fallback_set < 1) || (fallback_set > 3)) { ++ grub_dprintf ("atkeyb", "WARNING: ignoring unexpected value '%s' for '%s' variable\n", ++ envvar, "at_keyboard_fallback_set"); ++ fallback_set = 0; ++ } else { ++ grub_dprintf ("atkeyb", "query_mode: '%s' specified in environment, returning %d\n", ++ "at_keyboard_fallback_set", fallback_set); ++ } ++ return fallback_set; ++ } ++ grub_dprintf ("atkeyb", "WARNING: no '%s' specified in environment, returning 0\n", ++ "at_keyboard_fallback_set"); + return 0; + } + +@@ -167,15 +235,32 @@ set_scancodes (void) + { + /* You must have visited computer museum. Keyboard without scancode set + knowledge. Assume XT. */ +- if (!grub_keyboard_orig_set) +- { +- grub_dprintf ("atkeyb", "No sets support assumed\n"); +- ps2_state.current_set = 1; ++ if (!grub_keyboard_orig_set) { ++ if (fallback_set) { ++ grub_dprintf ("atkeyb", "No sets support assumed but set forced to %d\n", fallback_set); ++ ps2_state.current_set = fallback_set; + return; + } ++ grub_dprintf ("atkeyb", "No sets support assumed, forcing to set 1\n"); ++ ps2_state.current_set = 1; ++ return; ++ } + + #if !USE_SCANCODE_SET +- ps2_state.current_set = 1; ++ if (fallback_set) { ++ grub_dprintf ("atkeyb", "queried set is %d but set forced to %d\n", ++ grub_keyboard_orig_set, fallback_set); ++ ps2_state.current_set = fallback_set; ++ return; ++ } ++ ++ if ((grub_keyboard_controller_orig & KEYBOARD_AT_TRANSLATE) == KEYBOARD_AT_TRANSLATE) { ++ grub_dprintf ("atkeyb", "queried set is %d but keyboard in Translate mode, so actually in set 1\n", grub_keyboard_orig_set); ++ ps2_state.current_set = 1; ++ } else { ++ grub_dprintf ("atkeyb", "using queried set %d\n", grub_keyboard_orig_set); ++ ps2_state.current_set = grub_keyboard_orig_set; ++ } + return; + #else + +@@ -257,6 +342,7 @@ grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused))) + static void + grub_keyboard_controller_init (void) + { ++ grub_dprintf ("atkeyb", "initializing the controller\n"); + ps2_state.at_keyboard_status = 0; + /* Drain input buffer. */ + while (1) +@@ -276,7 +362,9 @@ grub_keyboard_controller_init (void) + grub_keyboard_orig_set = 2; + #else + grub_keyboard_controller_orig = grub_keyboard_controller_read (); ++ grub_dprintf ("atkeyb", "grub_keyboard_controller_orig = 0x%x\n", grub_keyboard_controller_orig); + grub_keyboard_orig_set = query_mode (); ++ grub_dprintf ("atkeyb", "grub_keyboard_orig_set = %d\n", grub_keyboard_orig_set); + #endif + set_scancodes (); + keyboard_controller_led (ps2_state.led_status); +@@ -285,11 +373,15 @@ grub_keyboard_controller_init (void) + static grub_err_t + grub_keyboard_controller_fini (struct grub_term_input *term __attribute__ ((unused))) + { ++/* In !USE_SCANCODE_SET mode, we didn't change anything, so nothing to restore */ ++#if USE_SCANCODE_SET + if (ps2_state.current_set == 0) + return GRUB_ERR_NONE; ++ grub_dprintf ("atkeyb", "restoring set %d, controller 0x%x\n", grub_keyboard_orig_set, grub_keyboard_controller_orig); + if (grub_keyboard_orig_set) + write_mode (grub_keyboard_orig_set); + grub_keyboard_controller_write (grub_keyboard_controller_orig); ++#endif + return GRUB_ERR_NONE; + } + +@@ -320,7 +412,6 @@ grub_at_restore_hw (void) + return GRUB_ERR_NONE; + } + +- + static struct grub_term_input grub_at_keyboard_term = + { + .name = "at_keyboard", +diff --git a/grub-core/term/terminfo.c b/grub-core/term/terminfo.c +index 4e534c683..3dbe88e89 100644 +--- a/grub-core/term/terminfo.c ++++ b/grub-core/term/terminfo.c +@@ -151,7 +151,7 @@ grub_terminfo_set_current (struct grub_term_output *term, + /* Clear the screen. Using serial console, screen(1) only recognizes the + * ANSI escape sequence. Using video console, Apple Open Firmware + * (version 3.1.1) only recognizes the literal ^L. So use both. */ +- data->cls = grub_strdup (" \e[2J"); ++ data->cls = grub_strdup ("\x0c\e[2J\e[m"); + data->reverse_video_on = grub_strdup ("\e[7m"); + data->reverse_video_off = grub_strdup ("\e[m"); + if (grub_strcmp ("ieee1275", str) == 0) +diff --git a/grub-core/tests/appended_signature_test.c b/grub-core/tests/appended_signature_test.c +new file mode 100644 +index 000000000..dbba06166 +--- /dev/null ++++ b/grub-core/tests/appended_signature_test.c +@@ -0,0 +1,306 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "appended_signatures.h" ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++#define DEFINE_TEST_CASE(case_name) \ ++static char * \ ++get_ ## case_name (grub_size_t *sz) \ ++{ \ ++ char *ret; \ ++ *sz = case_name ## _len; \ ++ ret = grub_malloc (*sz); \ ++ if (ret) \ ++ grub_memcpy (ret, case_name, *sz); \ ++ return ret; \ ++} \ ++\ ++static struct grub_procfs_entry case_name ## _entry = \ ++{ \ ++ .name = #case_name, \ ++ .get_contents = get_ ## case_name \ ++} ++ ++#define DO_TEST(case_name, is_valid) \ ++{ \ ++ grub_procfs_register (#case_name, &case_name ## _entry); \ ++ do_verify ("(proc)/" #case_name, is_valid); \ ++ grub_procfs_unregister (&case_name ## _entry); \ ++} ++ ++ ++DEFINE_TEST_CASE (hi_signed); ++DEFINE_TEST_CASE (hi_signed_sha256); ++DEFINE_TEST_CASE (hj_signed); ++DEFINE_TEST_CASE (short_msg); ++DEFINE_TEST_CASE (unsigned_msg); ++DEFINE_TEST_CASE (hi_signed_2nd); ++ ++static char * ++get_certificate_der (grub_size_t * sz) ++{ ++ char *ret; ++ *sz = certificate_der_len; ++ ret = grub_malloc (*sz); ++ if (ret) ++ grub_memcpy (ret, certificate_der, *sz); ++ return ret; ++} ++ ++static struct grub_procfs_entry certificate_der_entry = { ++ .name = "certificate.der", ++ .get_contents = get_certificate_der ++}; ++ ++static char * ++get_certificate2_der (grub_size_t * sz) ++{ ++ char *ret; ++ *sz = certificate2_der_len; ++ ret = grub_malloc (*sz); ++ if (ret) ++ grub_memcpy (ret, certificate2_der, *sz); ++ return ret; ++} ++ ++static struct grub_procfs_entry certificate2_der_entry = { ++ .name = "certificate2.der", ++ .get_contents = get_certificate2_der ++}; ++ ++static char * ++get_certificate_printable_der (grub_size_t * sz) ++{ ++ char *ret; ++ *sz = certificate_printable_der_len; ++ ret = grub_malloc (*sz); ++ if (ret) ++ grub_memcpy (ret, certificate_printable_der, *sz); ++ return ret; ++} ++ ++static struct grub_procfs_entry certificate_printable_der_entry = { ++ .name = "certificate_printable.der", ++ .get_contents = get_certificate_printable_der ++}; ++ ++static char * ++get_certificate_eku_der (grub_size_t * sz) ++{ ++ char *ret; ++ *sz = certificate_eku_der_len; ++ ret = grub_malloc (*sz); ++ if (ret) ++ grub_memcpy (ret, certificate_eku_der, *sz); ++ return ret; ++} ++ ++static struct grub_procfs_entry certificate_eku_der_entry = { ++ .name = "certificate_eku.der", ++ .get_contents = get_certificate_eku_der ++}; ++ ++ ++static void ++do_verify (const char *f, int is_valid) ++{ ++ grub_command_t cmd; ++ char *args[] = { (char *) f, NULL }; ++ grub_err_t err; ++ ++ cmd = grub_command_find ("verify_appended"); ++ if (!cmd) ++ { ++ grub_test_assert (0, "can't find command `%s'", "verify_appended"); ++ return; ++ } ++ err = (cmd->func) (cmd, 1, args); ++ if (is_valid) ++ { ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "verification of %s failed: %d: %s", f, grub_errno, ++ grub_errmsg); ++ } ++ else ++ { ++ grub_test_assert (err == GRUB_ERR_BAD_SIGNATURE, ++ "verification of %s unexpectedly succeeded", f); ++ } ++ grub_errno = GRUB_ERR_NONE; ++ ++} ++ ++static void ++appended_signature_test (void) ++{ ++ grub_command_t cmd_trust, cmd_distrust; ++ char *trust_args[] = { (char *) "(proc)/certificate.der", NULL }; ++ char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL }; ++ char *trust_args_printable[] = { (char *) "(proc)/certificate_printable.der", ++ NULL }; ++ char *trust_args_eku[] = { (char *) "(proc)/certificate_eku.der", NULL }; ++ char *distrust_args[] = { (char *) "1", NULL }; ++ char *distrust2_args[] = { (char *) "2", NULL }; ++ grub_err_t err; ++ ++ grub_procfs_register ("certificate.der", &certificate_der_entry); ++ grub_procfs_register ("certificate2.der", &certificate2_der_entry); ++ grub_procfs_register ("certificate_printable.der", ++ &certificate_printable_der_entry); ++ grub_procfs_register ("certificate_eku.der", &certificate_eku_der_entry); ++ ++ cmd_trust = grub_command_find ("trust_certificate"); ++ if (!cmd_trust) ++ { ++ grub_test_assert (0, "can't find command `%s'", "trust_certificate"); ++ return; ++ } ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args); ++ ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "loading certificate failed: %d: %s", grub_errno, ++ grub_errmsg); ++ ++ /* If we have no certificate the remainder of the tests are meaningless */ ++ if (err != GRUB_ERR_NONE) ++ return; ++ ++ /* ++ * Reload the command: this works around some 'interesting' behaviour in the ++ * dynamic command dispatcher. The first time you call cmd->func you get a ++ * dispatcher that loads the module, finds the real cmd, calls it, and then ++ * releases some internal storage. This means it's not safe to call a second ++ * time and we need to reload it. ++ */ ++ cmd_trust = grub_command_find ("trust_certificate"); ++ ++ DO_TEST (hi_signed, 1); ++ DO_TEST (hi_signed_sha256, 1); ++ DO_TEST (hj_signed, 0); ++ DO_TEST (short_msg, 0); ++ DO_TEST (unsigned_msg, 0); ++ ++ /* ++ * in enforcing mode, we shouldn't be able to load a certificate that isn't ++ * signed by an existing trusted key. ++ * ++ * However, procfs files automatically skip the verification test, so we can't ++ * easily test this. ++ */ ++ ++ /* ++ * verify that testing with 2 trusted certs works ++ */ ++ DO_TEST (hi_signed_2nd, 0); ++ ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args2); ++ ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "loading certificate 2 failed: %d: %s", grub_errno, ++ grub_errmsg); ++ ++ if (err != GRUB_ERR_NONE) ++ return; ++ ++ DO_TEST (hi_signed_2nd, 1); ++ DO_TEST (hi_signed, 1); ++ ++ /* ++ * Check certificate removal. They're added to the _top_ of the list and ++ * removed by position in the list. Current the list looks like [#2, #1]. ++ * ++ * First test removing the second certificate in the list, which is ++ * certificate #1, giving us just [#2]. ++ */ ++ cmd_distrust = grub_command_find ("distrust_certificate"); ++ if (!cmd_distrust) ++ { ++ grub_test_assert (0, "can't find command `%s'", "distrust_certificate"); ++ return; ++ } ++ ++ err = (cmd_distrust->func) (cmd_distrust, 1, distrust2_args); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "distrusting certificate 1 failed: %d: %s", grub_errno, ++ grub_errmsg); ++ DO_TEST (hi_signed_2nd, 1); ++ DO_TEST (hi_signed, 0); ++ ++ /* ++ * Now reload certificate #1. This will make the list look like [#1, #2] ++ */ ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args); ++ ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "reloading certificate 1 failed: %d: %s", grub_errno, ++ grub_errmsg); ++ DO_TEST (hi_signed, 1); ++ ++ /* Remove the first certificate in the list, giving us just [#2] */ ++ err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "distrusting certificate 1 (first time) failed: %d: %s", ++ grub_errno, grub_errmsg); ++ DO_TEST (hi_signed_2nd, 1); ++ DO_TEST (hi_signed, 0); ++ ++ /* ++ * Remove the first certificate again, giving an empty list. ++ * ++ * verify_appended should fail if there are no certificates to verify against. ++ */ ++ err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "distrusting certificate 1 (second time) failed: %d: %s", ++ grub_errno, grub_errmsg); ++ DO_TEST (hi_signed_2nd, 0); ++ ++ /* ++ * Lastly, check a certificate that uses printableString rather than ++ * utf8String loads properly, and that a certificate with an appropriate ++ * extended key usage loads. ++ */ ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "trusting printable certificate failed: %d: %s", ++ grub_errno, grub_errmsg); ++ ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args_eku); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "trusting certificate with extended key usage failed: %d: %s", ++ grub_errno, grub_errmsg); ++ ++ grub_procfs_unregister (&certificate_der_entry); ++ grub_procfs_unregister (&certificate2_der_entry); ++ grub_procfs_unregister (&certificate_printable_der_entry); ++ grub_procfs_unregister (&certificate_eku_der_entry); ++} ++ ++GRUB_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test); +diff --git a/grub-core/tests/appended_signatures.h b/grub-core/tests/appended_signatures.h +new file mode 100644 +index 000000000..2e5ebd7d8 +--- /dev/null ++++ b/grub-core/tests/appended_signatures.h +@@ -0,0 +1,638 @@ ++unsigned char certificate_der[] = { ++ 0x30, 0x82, 0x03, 0x88, 0x30, 0x82, 0x02, 0x70, 0xa0, 0x03, 0x02, 0x01, ++ 0x02, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d, ++ 0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30, ++ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, ++ 0x05, 0x00, 0x30, 0x49, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, ++ 0x03, 0x0c, 0x1f, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, ++ 0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, ++ 0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d, ++ 0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, ++ 0x01, 0x16, 0x0e, 0x64, 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, ++ 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30, ++ 0x37, 0x30, 0x39, 0x30, 0x36, 0x32, 0x32, 0x30, 0x37, 0x5a, 0x18, 0x0f, ++ 0x32, 0x31, 0x32, 0x30, 0x30, 0x36, 0x31, 0x35, 0x30, 0x36, 0x32, 0x32, ++ 0x30, 0x37, 0x5a, 0x30, 0x52, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, ++ 0x04, 0x03, 0x0c, 0x28, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, ++ 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, ++ 0x75, 0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x69, 0x67, ++ 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x31, 0x1d, 0x30, 0x1b, ++ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, ++ 0x0e, 0x64, 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, ++ 0x6e, 0x65, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, ++ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, ++ 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, ++ 0xcd, 0xe8, 0x1c, 0x08, 0x68, 0x2e, 0xcb, 0xfe, 0x8c, 0x4b, 0x3b, 0x61, ++ 0xe7, 0x8e, 0x80, 0x58, 0x85, 0x85, 0xea, 0xc8, 0x3b, 0x42, 0xba, 0x72, ++ 0x84, 0x65, 0x20, 0xbc, 0x48, 0xa2, 0x25, 0x49, 0x6e, 0x1c, 0xb9, 0x7d, ++ 0xeb, 0xc1, 0x0c, 0xa8, 0xb7, 0xcc, 0x13, 0x78, 0xba, 0x11, 0xa4, 0x98, ++ 0xd7, 0xd0, 0x7c, 0xdd, 0xf5, 0x5a, 0xb7, 0xcd, 0x31, 0x0e, 0xcd, 0x9e, ++ 0xa7, 0x19, 0xf0, 0xbd, 0x0f, 0xa6, 0xfe, 0x8a, 0x11, 0x97, 0xed, 0x8b, ++ 0xe5, 0x16, 0xa6, 0x21, 0x13, 0x36, 0xad, 0x05, 0x49, 0xec, 0x29, 0x12, ++ 0x38, 0xa7, 0x4b, 0x0f, 0xa1, 0xfb, 0x72, 0xc0, 0xc0, 0x09, 0x67, 0x78, ++ 0xa8, 0xb6, 0xd6, 0x1a, 0x39, 0xc0, 0xa8, 0xbf, 0x5f, 0x14, 0x89, 0x5c, ++ 0xbc, 0x41, 0x0c, 0x0c, 0x5d, 0x42, 0x2e, 0x1c, 0xdf, 0x1f, 0x1d, 0xc9, ++ 0x43, 0x94, 0x5b, 0x6e, 0x8f, 0x15, 0x8c, 0x8f, 0x94, 0x73, 0x4f, 0x97, ++ 0x54, 0xf1, 0x86, 0x8a, 0xbc, 0xe4, 0xe4, 0x93, 0xc1, 0x5e, 0xc2, 0x3e, ++ 0x31, 0x5e, 0xd4, 0x85, 0x57, 0x14, 0xd0, 0x11, 0x07, 0x65, 0xf4, 0x7c, ++ 0x8f, 0x07, 0x57, 0xe1, 0x22, 0xd4, 0x78, 0x47, 0x65, 0x4e, 0xa9, 0xb3, ++ 0xaa, 0xce, 0xc7, 0x36, 0xfe, 0xda, 0x66, 0x02, 0xb6, 0x8d, 0x18, 0x2f, ++ 0x3b, 0x41, 0x8d, 0x02, 0x08, 0x72, 0x4b, 0x69, 0xbd, 0x1e, 0x58, 0xfc, ++ 0x1b, 0x64, 0x04, 0x52, 0x35, 0x35, 0xe2, 0x3d, 0x3e, 0xde, 0xd6, 0x64, ++ 0xf4, 0xec, 0x57, 0x7e, 0x65, 0x59, 0x00, 0xa6, 0xd3, 0x4b, 0x09, 0x93, ++ 0x2a, 0x95, 0x0f, 0x30, 0xb6, 0xa1, 0x8c, 0xe7, 0x8b, 0x49, 0xa4, 0x1d, ++ 0x25, 0x2d, 0x65, 0x48, 0x8a, 0x0f, 0xcf, 0x2a, 0xa2, 0xe1, 0xef, 0x72, ++ 0x92, 0xc3, 0xf5, 0x21, 0x37, 0x83, 0x9b, 0x6d, 0x0b, 0x1b, 0xb3, 0xa2, ++ 0x32, 0x38, 0x11, 0xb1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30, ++ 0x5b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, ++ 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, ++ 0x03, 0x02, 0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, ++ 0x16, 0x04, 0x14, 0xe5, 0x2a, 0x4f, 0xf2, 0x84, 0x91, 0x57, 0x91, 0xaf, ++ 0x12, 0xd2, 0xf1, 0xa1, 0x87, 0x73, 0x0f, 0x90, 0x25, 0xa0, 0x7a, 0x30, ++ 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, ++ 0x56, 0xd1, 0xfd, 0xe2, 0x1e, 0x7e, 0x1c, 0x63, 0x4f, 0x47, 0xdb, 0xe4, ++ 0xc4, 0x51, 0x04, 0x03, 0x9a, 0x48, 0x35, 0x6e, 0x30, 0x0d, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, ++ 0x82, 0x01, 0x01, 0x00, 0x65, 0x82, 0xd5, 0x88, 0x30, 0xe2, 0x2c, 0x47, ++ 0xf3, 0x31, 0x39, 0xa1, 0x75, 0x9a, 0xb0, 0x8a, 0x6c, 0x4b, 0xac, 0xdf, ++ 0x09, 0x7b, 0x90, 0xb6, 0x9e, 0x76, 0x62, 0x94, 0xc1, 0x3a, 0x99, 0x49, ++ 0x68, 0x29, 0x47, 0x42, 0xc3, 0x06, 0xcb, 0x88, 0x75, 0xe6, 0x79, 0x13, ++ 0x8c, 0x4b, 0x49, 0x6a, 0xb5, 0x56, 0x95, 0xc0, 0x42, 0x21, 0x9b, 0xd4, ++ 0x61, 0xd0, 0x02, 0x41, 0xdd, 0x20, 0x61, 0xe5, 0x91, 0xdf, 0x75, 0x00, ++ 0x25, 0x0e, 0x99, 0x65, 0x5c, 0x54, 0x49, 0x32, 0xa3, 0xe2, 0xcd, 0xa1, ++ 0x5f, 0x40, 0xf3, 0xc5, 0x81, 0xd9, 0x3c, 0xa3, 0x63, 0x5a, 0x38, 0x79, ++ 0xab, 0x77, 0x98, 0xde, 0x8f, 0x4e, 0x9e, 0x26, 0xbc, 0x4e, 0x80, 0x9e, ++ 0x8f, 0xbe, 0xf1, 0x00, 0xb3, 0x78, 0xb9, 0x4b, 0x1d, 0xc7, 0xa4, 0x83, ++ 0x59, 0x56, 0x11, 0xd1, 0x11, 0x1e, 0x50, 0x39, 0xd5, 0x78, 0x14, 0xf3, ++ 0xb9, 0x1d, 0xda, 0xe4, 0xc4, 0x63, 0x74, 0x26, 0xab, 0xa3, 0xfd, 0x9d, ++ 0x58, 0xa2, 0xee, 0x7b, 0x28, 0x34, 0xa3, 0xbe, 0x85, 0x7e, 0xaa, 0x97, ++ 0xb7, 0x5b, 0x9d, 0xa9, 0x4d, 0x96, 0xdb, 0x6b, 0x21, 0xe1, 0x96, 0x5d, ++ 0xc7, 0xad, 0x23, 0x03, 0x9a, 0x16, 0xdb, 0xa4, 0x1f, 0x63, 0xef, 0xaf, ++ 0x1e, 0x4f, 0xf8, 0x27, 0xdc, 0x4b, 0xfc, 0x2b, 0x68, 0x2e, 0xa0, 0xd3, ++ 0xae, 0xf2, 0xce, 0xf5, 0xfc, 0x97, 0x92, 0xd2, 0x29, 0x0f, 0x4f, 0x4b, ++ 0x29, 0xeb, 0x06, 0xcb, 0xf8, 0x21, 0x6e, 0xbc, 0x8b, 0x5c, 0xc5, 0xc9, ++ 0xf7, 0xe2, 0x7c, 0x47, 0xcd, 0x43, 0x98, 0xc4, 0xa3, 0x9a, 0xd7, 0x3e, ++ 0xdc, 0x01, 0x13, 0x28, 0x96, 0xc4, 0x60, 0x83, 0xe2, 0x79, 0xa1, 0x46, ++ 0xef, 0xf5, 0xa4, 0x7b, 0x00, 0xe3, 0x3d, 0x7d, 0xbc, 0xa8, 0x98, 0x49, ++ 0xa8, 0xcf, 0x3b, 0x41, 0xb6, 0x09, 0x97, 0x07 ++}; ++unsigned int certificate_der_len = 908; ++ ++unsigned char hi_signed[] = { ++ 0x68, 0x69, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82, ++ 0x01, 0xad, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, ++ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x01, ++ 0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49, ++ 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x47, ++ 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, ++ 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, ++ 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64, ++ 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65, ++ 0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d, ++ 0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30, ++ 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xc7, 0x69, 0x35, 0x21, 0x66, ++ 0x4d, 0x50, 0xd4, 0x73, 0xde, 0xbd, 0x3a, 0xf6, 0x45, 0xe3, 0xe4, 0xd0, ++ 0xb6, 0xa1, 0xe7, 0xc0, 0xa2, 0xc9, 0xf4, 0xf0, 0x05, 0x8c, 0xa4, 0x16, ++ 0x9e, 0x81, 0x0d, 0x21, 0x68, 0xf3, 0xfe, 0x03, 0x96, 0x77, 0x31, 0x69, ++ 0x01, 0xd8, 0x26, 0xd9, 0x48, 0x95, 0xcf, 0xd1, 0x17, 0xb1, 0x0b, 0x6b, ++ 0x2c, 0xf1, 0xb0, 0xab, 0x65, 0x65, 0x56, 0xf8, 0x0c, 0xa7, 0xf7, 0xbb, ++ 0xf6, 0x5a, 0x55, 0x98, 0x14, 0x07, 0x8d, 0x2a, 0xbc, 0x16, 0x48, 0x94, ++ 0xab, 0x2f, 0x85, 0x97, 0x90, 0x51, 0x78, 0xa0, 0xda, 0x60, 0xb5, 0x41, ++ 0x4b, 0xe8, 0x78, 0xc5, 0xa6, 0x04, 0x9d, 0x54, 0x2a, 0x85, 0xfd, 0x86, ++ 0x0b, 0x6d, 0xc2, 0xd2, 0xad, 0x07, 0xff, 0x16, 0x42, 0x82, 0xe3, 0x5c, ++ 0xaa, 0x22, 0x59, 0x78, 0x92, 0xea, 0x94, 0xc3, 0x41, 0xb7, 0xa1, 0x86, ++ 0x44, 0xea, 0xd1, 0xdb, 0xe5, 0xac, 0x30, 0x32, 0xfb, 0x7d, 0x3f, 0xf7, ++ 0x8b, 0x11, 0x7f, 0x80, 0x3b, 0xe5, 0xc7, 0x82, 0x0f, 0x92, 0x07, 0x14, ++ 0x66, 0x01, 0x6e, 0x85, 0xab, 0x3a, 0x14, 0xcf, 0x76, 0xd1, 0x7e, 0x14, ++ 0x85, 0xca, 0x01, 0x73, 0x72, 0x38, 0xdc, 0xde, 0x30, 0x5c, 0xfb, 0xc0, ++ 0x3d, 0x93, 0xef, 0x9c, 0xbc, 0xf8, 0xcc, 0xd2, 0xbf, 0x47, 0xec, 0xf8, ++ 0x88, 0x9b, 0xe1, 0x43, 0xbe, 0xa7, 0x47, 0x96, 0xb6, 0x5d, 0x46, 0x0e, ++ 0x7a, 0x78, 0x38, 0x19, 0xbc, 0xb5, 0xbc, 0x9b, 0x3c, 0x39, 0x92, 0x70, ++ 0x0d, 0x9d, 0x8a, 0x35, 0xaf, 0xb4, 0x9e, 0xf4, 0xef, 0xc1, 0xb8, 0x25, ++ 0xd0, 0x14, 0x91, 0xd6, 0xc2, 0xb6, 0xc7, 0x3c, 0x72, 0x91, 0x0f, 0xad, ++ 0xde, 0xb2, 0x36, 0xf8, 0x4e, 0x59, 0xd4, 0xa4, 0x21, 0x9f, 0x03, 0x95, ++ 0x48, 0x01, 0xb4, 0x05, 0xc3, 0x39, 0x60, 0x51, 0x08, 0xd0, 0xbe, 0x00, ++ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x7e, ++ 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, ++ 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, ++ 0x64, 0x7e, 0x0a ++}; ++unsigned int hi_signed_len = 495; ++ ++unsigned char hj_signed[] = { ++ 0x68, 0x6a, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82, ++ 0x01, 0xad, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, ++ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x01, ++ 0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49, ++ 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x47, ++ 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, ++ 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, ++ 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64, ++ 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65, ++ 0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d, ++ 0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30, ++ 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xc7, 0x69, 0x35, 0x21, 0x66, ++ 0x4d, 0x50, 0xd4, 0x73, 0xde, 0xbd, 0x3a, 0xf6, 0x45, 0xe3, 0xe4, 0xd0, ++ 0xb6, 0xa1, 0xe7, 0xc0, 0xa2, 0xc9, 0xf4, 0xf0, 0x05, 0x8c, 0xa4, 0x16, ++ 0x9e, 0x81, 0x0d, 0x21, 0x68, 0xf3, 0xfe, 0x03, 0x96, 0x77, 0x31, 0x69, ++ 0x01, 0xd8, 0x26, 0xd9, 0x48, 0x95, 0xcf, 0xd1, 0x17, 0xb1, 0x0b, 0x6b, ++ 0x2c, 0xf1, 0xb0, 0xab, 0x65, 0x65, 0x56, 0xf8, 0x0c, 0xa7, 0xf7, 0xbb, ++ 0xf6, 0x5a, 0x55, 0x98, 0x14, 0x07, 0x8d, 0x2a, 0xbc, 0x16, 0x48, 0x94, ++ 0xab, 0x2f, 0x85, 0x97, 0x90, 0x51, 0x78, 0xa0, 0xda, 0x60, 0xb5, 0x41, ++ 0x4b, 0xe8, 0x78, 0xc5, 0xa6, 0x04, 0x9d, 0x54, 0x2a, 0x85, 0xfd, 0x86, ++ 0x0b, 0x6d, 0xc2, 0xd2, 0xad, 0x07, 0xff, 0x16, 0x42, 0x82, 0xe3, 0x5c, ++ 0xaa, 0x22, 0x59, 0x78, 0x92, 0xea, 0x94, 0xc3, 0x41, 0xb7, 0xa1, 0x86, ++ 0x44, 0xea, 0xd1, 0xdb, 0xe5, 0xac, 0x30, 0x32, 0xfb, 0x7d, 0x3f, 0xf7, ++ 0x8b, 0x11, 0x7f, 0x80, 0x3b, 0xe5, 0xc7, 0x82, 0x0f, 0x92, 0x07, 0x14, ++ 0x66, 0x01, 0x6e, 0x85, 0xab, 0x3a, 0x14, 0xcf, 0x76, 0xd1, 0x7e, 0x14, ++ 0x85, 0xca, 0x01, 0x73, 0x72, 0x38, 0xdc, 0xde, 0x30, 0x5c, 0xfb, 0xc0, ++ 0x3d, 0x93, 0xef, 0x9c, 0xbc, 0xf8, 0xcc, 0xd2, 0xbf, 0x47, 0xec, 0xf8, ++ 0x88, 0x9b, 0xe1, 0x43, 0xbe, 0xa7, 0x47, 0x96, 0xb6, 0x5d, 0x46, 0x0e, ++ 0x7a, 0x78, 0x38, 0x19, 0xbc, 0xb5, 0xbc, 0x9b, 0x3c, 0x39, 0x92, 0x70, ++ 0x0d, 0x9d, 0x8a, 0x35, 0xaf, 0xb4, 0x9e, 0xf4, 0xef, 0xc1, 0xb8, 0x25, ++ 0xd0, 0x14, 0x91, 0xd6, 0xc2, 0xb6, 0xc7, 0x3c, 0x72, 0x91, 0x0f, 0xad, ++ 0xde, 0xb2, 0x36, 0xf8, 0x4e, 0x59, 0xd4, 0xa4, 0x21, 0x9f, 0x03, 0x95, ++ 0x48, 0x01, 0xb4, 0x05, 0xc3, 0x39, 0x60, 0x51, 0x08, 0xd0, 0xbe, 0x00, ++ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x7e, ++ 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, ++ 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, ++ 0x64, 0x7e, 0x0a ++}; ++unsigned int hj_signed_len = 495; ++ ++unsigned char hi_signed_sha256[] = { ++ 0x68, 0x69, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82, ++ 0x01, 0xad, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, ++ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x01, ++ 0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49, ++ 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x47, ++ 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, ++ 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, ++ 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64, ++ 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65, ++ 0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d, ++ 0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30, ++ 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x7b, 0x5e, 0x82, 0x1d, 0x21, ++ 0xb6, 0x40, 0xd3, 0x33, 0x79, 0xa7, 0x52, 0x2b, 0xfc, 0x46, 0x51, 0x26, ++ 0xfe, 0x0f, 0x81, 0x90, 0x81, 0xab, 0x57, 0x5e, 0xf6, 0x45, 0x41, 0xa3, ++ 0x7b, 0x48, 0xdd, 0xd6, 0x59, 0x60, 0x51, 0x31, 0x14, 0x14, 0x7b, 0xb4, ++ 0x55, 0x7b, 0x4d, 0xfe, 0x09, 0x7a, 0x5d, 0xae, 0xc4, 0x58, 0x50, 0x80, ++ 0x75, 0xf2, 0x23, 0x20, 0x62, 0xe3, 0x7c, 0x26, 0x1d, 0x2a, 0x4d, 0x9f, ++ 0x89, 0xf0, 0x4f, 0x95, 0x8a, 0x80, 0x6e, 0x1a, 0xea, 0x87, 0xdb, 0x1f, ++ 0xf3, 0xda, 0x04, 0x91, 0x37, 0xea, 0x0a, 0xfb, 0x6c, 0xc9, 0x3d, 0x73, ++ 0xf9, 0x58, 0x7c, 0x15, 0x6b, 0xa2, 0x52, 0x5a, 0x97, 0xff, 0xd6, 0xb0, ++ 0xf1, 0xbf, 0xa5, 0x04, 0x6d, 0x91, 0xc1, 0x54, 0x05, 0xdc, 0x7f, 0x5d, ++ 0x19, 0xaf, 0x55, 0xec, 0x51, 0xfb, 0x66, 0x0a, 0xa4, 0x4e, 0x96, 0x47, ++ 0x43, 0x54, 0x7c, 0x64, 0xa8, 0xaa, 0xb4, 0x90, 0x02, 0xf3, 0xa7, 0x0b, ++ 0xb7, 0xbf, 0x06, 0xdb, 0x5e, 0x9c, 0x32, 0x6d, 0x45, 0x14, 0x1c, 0xaf, ++ 0x46, 0x30, 0x08, 0x55, 0x49, 0x78, 0xfa, 0x57, 0xda, 0x3d, 0xf5, 0xa0, ++ 0xef, 0x11, 0x0a, 0x81, 0x0d, 0x82, 0xcd, 0xaf, 0xdb, 0xda, 0x0e, 0x1a, ++ 0x44, 0xd1, 0xee, 0xc4, 0xb8, 0xde, 0x97, 0xb4, 0xda, 0xb4, 0x8b, 0x4f, ++ 0x58, 0x24, 0x59, 0xc0, 0xe0, 0x08, 0x97, 0x14, 0x68, 0xbe, 0x31, 0x09, ++ 0x5e, 0x67, 0x45, 0xf0, 0xcb, 0x81, 0x4f, 0x17, 0x44, 0x61, 0xe0, 0xe2, ++ 0xf0, 0xfc, 0x1e, 0xb9, 0x73, 0xaf, 0x42, 0xff, 0x33, 0xde, 0x61, 0x6b, ++ 0x7f, 0xc2, 0x69, 0x0d, 0x66, 0x54, 0xae, 0xf6, 0xde, 0x20, 0x47, 0x44, ++ 0x9b, 0x73, 0xd1, 0x07, 0x6e, 0x77, 0x37, 0x0a, 0xbb, 0x7f, 0xa0, 0x93, ++ 0x2d, 0x8d, 0x44, 0xba, 0xe2, 0xdd, 0x34, 0x32, 0xd7, 0x56, 0x71, 0x00, ++ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x7e, ++ 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, ++ 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, ++ 0x64, 0x7e, 0x0a ++}; ++unsigned int hi_signed_sha256_len = 495; ++ ++unsigned char short_msg[] = { ++ 0x68, 0x69, 0x0a ++}; ++unsigned int short_msg_len = 3; ++ ++unsigned char unsigned_msg[] = { ++ 0x53, 0x65, 0x64, 0x20, 0x75, 0x74, 0x20, 0x70, 0x65, 0x72, 0x73, 0x70, ++ 0x69, 0x63, 0x69, 0x61, 0x74, 0x69, 0x73, 0x20, 0x75, 0x6e, 0x64, 0x65, ++ 0x20, 0x6f, 0x6d, 0x6e, 0x69, 0x73, 0x20, 0x69, 0x73, 0x74, 0x65, 0x20, ++ 0x6e, 0x61, 0x74, 0x75, 0x73, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, ++ 0x73, 0x69, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74, ++ 0x65, 0x6d, 0x20, 0x61, 0x63, 0x63, 0x75, 0x73, 0x61, 0x6e, 0x74, 0x69, ++ 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x71, 0x75, ++ 0x65, 0x20, 0x6c, 0x61, 0x75, 0x64, 0x61, 0x6e, 0x74, 0x69, 0x75, 0x6d, ++ 0x2c, 0x20, 0x74, 0x6f, 0x74, 0x61, 0x6d, 0x20, 0x72, 0x65, 0x6d, 0x20, ++ 0x61, 0x70, 0x65, 0x72, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x65, 0x61, 0x71, ++ 0x75, 0x65, 0x20, 0x69, 0x70, 0x73, 0x61, 0x20, 0x71, 0x75, 0x61, 0x65, ++ 0x20, 0x61, 0x62, 0x20, 0x69, 0x6c, 0x6c, 0x6f, 0x20, 0x69, 0x6e, 0x76, ++ 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x76, 0x65, 0x72, 0x69, 0x74, ++ 0x61, 0x74, 0x69, 0x73, 0x20, 0x65, 0x74, 0x20, 0x71, 0x75, 0x61, 0x73, ++ 0x69, 0x20, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x6f, ++ 0x20, 0x62, 0x65, 0x61, 0x74, 0x61, 0x65, 0x20, 0x76, 0x69, 0x74, 0x61, ++ 0x65, 0x20, 0x64, 0x69, 0x63, 0x74, 0x61, 0x20, 0x73, 0x75, 0x6e, 0x74, ++ 0x20, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x62, 0x6f, 0x2e, 0x20, ++ 0x4e, 0x65, 0x6d, 0x6f, 0x20, 0x65, 0x6e, 0x69, 0x6d, 0x20, 0x69, 0x70, ++ 0x73, 0x61, 0x6d, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74, ++ 0x65, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75, ++ 0x70, 0x74, 0x61, 0x73, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x73, 0x70, ++ 0x65, 0x72, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x20, 0x61, 0x75, 0x74, 0x20, ++ 0x6f, 0x64, 0x69, 0x74, 0x20, 0x61, 0x75, 0x74, 0x20, 0x66, 0x75, 0x67, ++ 0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x64, 0x20, 0x71, 0x75, 0x69, 0x61, ++ 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x75, 0x6e, 0x74, 0x75, ++ 0x72, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, ++ 0x72, 0x65, 0x73, 0x20, 0x65, 0x6f, 0x73, 0x20, 0x71, 0x75, 0x69, 0x20, ++ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x20, 0x76, 0x6f, 0x6c, 0x75, ++ 0x70, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x20, 0x73, 0x65, 0x71, 0x75, 0x69, ++ 0x20, 0x6e, 0x65, 0x73, 0x63, 0x69, 0x75, 0x6e, 0x74, 0x2e, 0x20, 0x4e, ++ 0x65, 0x71, 0x75, 0x65, 0x20, 0x70, 0x6f, 0x72, 0x72, 0x6f, 0x20, 0x71, ++ 0x75, 0x69, 0x73, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x73, 0x74, 0x2c, ++ 0x20, 0x71, 0x75, 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, ++ 0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 0x20, ++ 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, ++ 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 0x65, ++ 0x74, 0x75, 0x72, 0x2c, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63, ++ 0x69, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x64, ++ 0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x6e, 0x6f, 0x6e, 0x20, 0x6e, 0x75, ++ 0x6d, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x69, 0x75, 0x73, 0x20, 0x6d, ++ 0x6f, 0x64, 0x69, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x20, ++ 0x69, 0x6e, 0x63, 0x69, 0x64, 0x75, 0x6e, 0x74, 0x20, 0x75, 0x74, 0x20, ++ 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x65, 0x20, 0x65, 0x74, 0x20, 0x64, 0x6f, ++ 0x6c, 0x6f, 0x72, 0x65, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x61, 0x6d, 0x20, ++ 0x61, 0x6c, 0x69, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x71, 0x75, 0x61, 0x65, ++ 0x72, 0x61, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74, ++ 0x65, 0x6d, 0x2e, 0x20, 0x55, 0x74, 0x20, 0x65, 0x6e, 0x69, 0x6d, 0x20, ++ 0x61, 0x64, 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x61, 0x20, 0x76, 0x65, ++ 0x6e, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x71, 0x75, 0x69, 0x73, 0x20, 0x6e, ++ 0x6f, 0x73, 0x74, 0x72, 0x75, 0x6d, 0x20, 0x65, 0x78, 0x65, 0x72, 0x63, ++ 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x6d, 0x20, 0x75, 0x6c, ++ 0x6c, 0x61, 0x6d, 0x20, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x69, 0x73, ++ 0x20, 0x73, 0x75, 0x73, 0x63, 0x69, 0x70, 0x69, 0x74, 0x20, 0x6c, 0x61, ++ 0x62, 0x6f, 0x72, 0x69, 0x6f, 0x73, 0x61, 0x6d, 0x2c, 0x20, 0x6e, 0x69, ++ 0x73, 0x69, 0x20, 0x75, 0x74, 0x20, 0x61, 0x6c, 0x69, 0x71, 0x75, 0x69, ++ 0x64, 0x20, 0x65, 0x78, 0x20, 0x65, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x6d, ++ 0x6f, 0x64, 0x69, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, ++ 0x74, 0x75, 0x72, 0x3f, 0x20, 0x51, 0x75, 0x69, 0x73, 0x20, 0x61, 0x75, ++ 0x74, 0x65, 0x6d, 0x20, 0x76, 0x65, 0x6c, 0x20, 0x65, 0x75, 0x6d, 0x20, ++ 0x69, 0x75, 0x72, 0x65, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x68, 0x65, ++ 0x6e, 0x64, 0x65, 0x72, 0x69, 0x74, 0x20, 0x71, 0x75, 0x69, 0x20, 0x69, ++ 0x6e, 0x20, 0x65, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, ++ 0x74, 0x65, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x20, 0x65, 0x73, 0x73, ++ 0x65, 0x20, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x6e, 0x69, 0x68, 0x69, 0x6c, ++ 0x20, 0x6d, 0x6f, 0x6c, 0x65, 0x73, 0x74, 0x69, 0x61, 0x65, 0x20, 0x63, ++ 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, 0x74, 0x75, 0x72, 0x2c, 0x20, ++ 0x76, 0x65, 0x6c, 0x20, 0x69, 0x6c, 0x6c, 0x75, 0x6d, 0x20, 0x71, 0x75, ++ 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x65, 0x75, ++ 0x6d, 0x20, 0x66, 0x75, 0x67, 0x69, 0x61, 0x74, 0x20, 0x71, 0x75, 0x6f, ++ 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x73, 0x20, 0x6e, 0x75, ++ 0x6c, 0x6c, 0x61, 0x20, 0x70, 0x61, 0x72, 0x69, 0x61, 0x74, 0x75, 0x72, ++ 0x3f, 0x0a ++}; ++unsigned int unsigned_msg_len = 866; ++ ++unsigned char certificate2_der[] = { ++ 0x30, 0x82, 0x05, 0x52, 0x30, 0x82, 0x03, 0x3a, 0xa0, 0x03, 0x02, 0x01, ++ 0x02, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, ++ 0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, ++ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, ++ 0x05, 0x00, 0x30, 0x3a, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, ++ 0x03, 0x0c, 0x2f, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, ++ 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, ++ 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, ++ 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, ++ 0x74, 0x79, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x37, 0x32, 0x38, ++ 0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x32, ++ 0x30, 0x30, 0x37, 0x30, 0x34, 0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 0x5a, ++ 0x30, 0x2b, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, ++ 0x20, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, ++ 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x69, ++ 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x82, 0x02, ++ 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, ++ 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, ++ 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xb0, 0x2f, 0x50, 0x01, 0x9c, 0x0e, ++ 0xd6, 0x8c, 0x07, 0xca, 0xc1, 0xcf, 0xbc, 0x03, 0xdd, 0xd3, 0xfa, 0xe3, ++ 0x4f, 0x71, 0xc1, 0x30, 0xaa, 0x09, 0x96, 0xe4, 0xd0, 0x6c, 0x42, 0x93, ++ 0xdb, 0x35, 0xf6, 0x7e, 0x1b, 0x67, 0xc0, 0xc2, 0x2d, 0x5b, 0xec, 0xca, ++ 0x35, 0x06, 0x32, 0x6c, 0x7b, 0x2c, 0xd3, 0x71, 0x2b, 0xe9, 0x7a, 0x19, ++ 0xd1, 0xf2, 0xa0, 0x7f, 0xd7, 0x4d, 0x6e, 0x28, 0xbb, 0xae, 0x49, 0x4a, ++ 0xbc, 0xea, 0x47, 0x67, 0xb8, 0x36, 0xa6, 0xf5, 0x0d, 0x0e, 0x20, 0x14, ++ 0x0c, 0x66, 0x67, 0x28, 0xb5, 0x97, 0x8b, 0x1f, 0x5e, 0x32, 0x06, 0x29, ++ 0x9c, 0x99, 0x92, 0x0f, 0x73, 0xac, 0xfd, 0xd2, 0x1d, 0xf2, 0xa8, 0x55, ++ 0x9d, 0x1b, 0xd8, 0x3d, 0xb0, 0x76, 0x9a, 0xb6, 0x6c, 0x9f, 0x62, 0x37, ++ 0x2f, 0xc0, 0xef, 0x44, 0xb3, 0x0d, 0x4a, 0x3e, 0x4f, 0x7d, 0xbd, 0xdb, ++ 0xd8, 0x75, 0x5f, 0x68, 0xe3, 0xf0, 0xec, 0x82, 0x66, 0x7c, 0x31, 0x70, ++ 0xa9, 0xa1, 0x6f, 0x38, 0x9f, 0xdf, 0xf5, 0xf0, 0x7d, 0x23, 0x9d, 0x34, ++ 0xa5, 0x85, 0xd3, 0xdf, 0x68, 0x41, 0xfc, 0x4f, 0x89, 0x45, 0x3c, 0x24, ++ 0x81, 0xa6, 0xf2, 0x3c, 0x02, 0x26, 0x09, 0x48, 0xdd, 0xfe, 0x4b, 0xb6, ++ 0x66, 0xbf, 0x8f, 0xe5, 0x5f, 0xf0, 0x5d, 0x8a, 0x61, 0x2e, 0x5f, 0x9f, ++ 0x80, 0xd9, 0xd5, 0xe6, 0x41, 0xd8, 0x10, 0x5e, 0x7a, 0xc6, 0xdb, 0x89, ++ 0xc7, 0xca, 0x6c, 0x5b, 0xb1, 0x4e, 0x7d, 0x0c, 0x03, 0xfd, 0x50, 0xca, ++ 0xbf, 0xbb, 0xe2, 0x69, 0x4b, 0x4e, 0xc2, 0x3d, 0x75, 0xfa, 0xd1, 0xcc, ++ 0xd6, 0xf9, 0x39, 0xb9, 0xdc, 0x53, 0xad, 0x62, 0xfb, 0x1b, 0x94, 0x26, ++ 0x7f, 0x21, 0x54, 0x5c, 0xb7, 0xdc, 0xe7, 0x96, 0x8c, 0xce, 0x75, 0xe0, ++ 0x17, 0x01, 0x3a, 0x3c, 0x77, 0x6e, 0xa4, 0x8b, 0x7a, 0x83, 0x28, 0x7a, ++ 0xf7, 0xb0, 0x5f, 0xfc, 0x7f, 0x2d, 0x2e, 0xec, 0xf5, 0xeb, 0x9c, 0x63, ++ 0x74, 0xd0, 0xe5, 0xdc, 0x19, 0xe4, 0x71, 0xc5, 0x4a, 0x8a, 0x54, 0xa4, ++ 0xe0, 0x7d, 0x4e, 0xbf, 0x53, 0x30, 0xaf, 0xd0, 0xeb, 0x96, 0xc3, 0xbb, ++ 0x65, 0xf7, 0x67, 0xf5, 0xae, 0xd3, 0x96, 0xf2, 0x63, 0xc8, 0x69, 0xf7, ++ 0x47, 0xcb, 0x27, 0x79, 0xe1, 0xff, 0x2f, 0x68, 0xdf, 0x1e, 0xb3, 0xb8, ++ 0x0c, 0xc5, 0x58, 0x73, 0xcc, 0xfe, 0x8c, 0xda, 0x4e, 0x3b, 0x01, 0x04, ++ 0xcd, 0xcb, 0xb8, 0x3e, 0x06, 0xfd, 0x4c, 0x0a, 0x9f, 0x5e, 0x76, 0x8c, ++ 0x0c, 0x83, 0x75, 0x09, 0x08, 0xb2, 0xdb, 0xf4, 0x49, 0x4e, 0xa0, 0xf2, ++ 0x0c, 0x7b, 0x87, 0x38, 0x9e, 0x22, 0x67, 0xbd, 0xd1, 0x97, 0x57, 0x24, ++ 0xf1, 0x46, 0x07, 0xf9, 0xd2, 0x1b, 0xec, 0x25, 0x5e, 0x67, 0xd9, 0x66, ++ 0x23, 0x1b, 0xd3, 0xe4, 0xaa, 0xec, 0x88, 0xf0, 0x7e, 0x15, 0x83, 0x51, ++ 0x31, 0x67, 0x51, 0x76, 0x5f, 0x55, 0xd7, 0x36, 0xdf, 0x4a, 0x84, 0x0b, ++ 0x6f, 0x5c, 0xbb, 0x5b, 0x8f, 0x37, 0x23, 0x7f, 0xf8, 0x17, 0x84, 0xa2, ++ 0x70, 0x20, 0x07, 0x0c, 0x90, 0x3a, 0x04, 0xfd, 0xf0, 0x08, 0x4a, 0xb1, ++ 0x16, 0x0f, 0xe6, 0xf6, 0x40, 0x51, 0x83, 0xd2, 0x87, 0x40, 0x9c, 0x1c, ++ 0x9f, 0x13, 0x38, 0x17, 0xd3, 0x34, 0x58, 0xad, 0x05, 0x71, 0xa0, 0x73, ++ 0xca, 0x40, 0xa6, 0xa4, 0x81, 0x02, 0xee, 0xa8, 0x72, 0x41, 0xa1, 0x41, ++ 0x18, 0x64, 0x8a, 0x86, 0x8a, 0x5d, 0xe6, 0x4f, 0x0a, 0xc5, 0x95, 0x98, ++ 0xf9, 0x78, 0xfe, 0x19, 0x0d, 0xc9, 0xb3, 0x89, 0xc1, 0x2b, 0x09, 0xbe, ++ 0xf1, 0xd2, 0x04, 0x5d, 0xcc, 0x28, 0xf5, 0x4b, 0xd2, 0x20, 0x4f, 0xc5, ++ 0x41, 0x9d, 0x8c, 0x85, 0xd8, 0xb0, 0x68, 0x5e, 0xc1, 0x0c, 0xb7, 0x24, ++ 0x4d, 0x67, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30, ++ 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, ++ 0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, ++ 0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, ++ 0x14, 0xac, 0xf5, 0x47, 0x17, 0xd9, 0x7d, 0xc1, 0xb1, 0xc4, 0x41, 0xe1, ++ 0x41, 0x60, 0xcb, 0x37, 0x11, 0x60, 0x28, 0x78, 0x5f, 0x30, 0x1f, 0x06, ++ 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x21, 0x94, ++ 0xfb, 0xf9, 0xb2, 0x43, 0xe9, 0x33, 0xd7, 0x50, 0x7d, 0xc7, 0x37, 0xdb, ++ 0xd5, 0x82, 0x5a, 0x4e, 0xbe, 0x1b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, ++ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, ++ 0x01, 0x00, 0x96, 0x70, 0x65, 0x26, 0x42, 0xf8, 0xdc, 0x69, 0xde, 0xcf, ++ 0x41, 0x3a, 0x2e, 0x7f, 0x5b, 0xf1, 0xf9, 0x3b, 0x9b, 0xd2, 0x4e, 0x64, ++ 0x48, 0x81, 0xe4, 0x5d, 0x1e, 0x22, 0xce, 0x68, 0x63, 0x62, 0xe5, 0x1b, ++ 0x9b, 0xf2, 0xc7, 0x12, 0xda, 0x1e, 0x9b, 0x90, 0x84, 0x79, 0x48, 0x12, ++ 0xe6, 0x21, 0x6f, 0x2f, 0x7e, 0x18, 0x77, 0xdb, 0x8c, 0xc4, 0xd1, 0x0d, ++ 0x91, 0xbf, 0x39, 0x22, 0x0f, 0x64, 0xcf, 0x25, 0x2e, 0x8c, 0x1f, 0x91, ++ 0x81, 0xb5, 0xe9, 0x6c, 0x02, 0x3a, 0xf8, 0x07, 0xa2, 0x6f, 0x46, 0x5d, ++ 0x7b, 0xfd, 0x43, 0xff, 0x41, 0x0f, 0xe2, 0x57, 0x1c, 0xbd, 0x48, 0x60, ++ 0x53, 0x11, 0x48, 0x87, 0x88, 0x9d, 0x13, 0x82, 0x40, 0x68, 0x44, 0x2c, ++ 0xc6, 0xc8, 0x95, 0x27, 0x4f, 0xb6, 0xb9, 0x4a, 0x22, 0x0a, 0xfd, 0xe4, ++ 0x46, 0x8f, 0x35, 0x12, 0x98, 0x5a, 0x34, 0x6f, 0x2b, 0x57, 0x62, 0xa1, ++ 0x4d, 0x8d, 0x79, 0x37, 0xe4, 0x6b, 0x8a, 0x32, 0x5b, 0xcb, 0xef, 0x79, ++ 0x11, 0xed, 0xa7, 0xf8, 0x7a, 0x1c, 0xbd, 0x86, 0xdc, 0x0e, 0x2e, 0xfd, ++ 0xd3, 0x51, 0xbb, 0x73, 0xad, 0x00, 0xa0, 0x1b, 0xf9, 0x1d, 0xd1, 0x4a, ++ 0xe4, 0xd4, 0x02, 0x63, 0x2b, 0x39, 0x5f, 0x18, 0x08, 0x2f, 0x42, 0xb7, ++ 0x23, 0x4b, 0x48, 0x46, 0x1f, 0x63, 0x87, 0xae, 0x6d, 0xd5, 0xdb, 0x60, ++ 0xf8, 0x5f, 0xd3, 0x13, 0xec, 0xca, 0xdd, 0x60, 0x60, 0x79, 0x52, 0x70, ++ 0x47, 0xae, 0x1d, 0x38, 0x78, 0x71, 0xcf, 0xb3, 0x04, 0x03, 0xbe, 0xba, ++ 0x81, 0xba, 0x74, 0xb1, 0x30, 0x35, 0xdc, 0xea, 0x21, 0x4a, 0x9b, 0x70, ++ 0xfb, 0xd6, 0x60, 0x59, 0x78, 0x0c, 0x4d, 0x39, 0x19, 0x1d, 0xe5, 0x75, ++ 0xba, 0x07, 0xf4, 0x22, 0x37, 0x64, 0xb7, 0xf2, 0x9a, 0xc9, 0x11, 0x2d, ++ 0x8e, 0x58, 0xa6, 0xcf, 0x83, 0xf1, 0xcb, 0x6c, 0x7f, 0x02, 0xbd, 0xda, ++ 0x03, 0x92, 0xa9, 0x45, 0x24, 0x56, 0xc5, 0xbd, 0x41, 0xd1, 0x20, 0x86, ++ 0xc0, 0xb6, 0xb7, 0xe8, 0xa7, 0xb2, 0x46, 0xf7, 0x8e, 0xa9, 0x38, 0x0e, ++ 0x23, 0x77, 0x3c, 0x0d, 0x66, 0x83, 0x6a, 0x1a, 0x6b, 0x7f, 0x54, 0x11, ++ 0x58, 0x0d, 0x4a, 0xb5, 0x74, 0x60, 0xca, 0xed, 0xff, 0x91, 0x47, 0xd9, ++ 0x29, 0xe0, 0xaa, 0x8c, 0xa8, 0x8f, 0x10, 0x4c, 0x15, 0x7d, 0xce, 0x95, ++ 0xf9, 0x87, 0x1e, 0x18, 0x38, 0x18, 0xfc, 0xcc, 0xaf, 0x91, 0x17, 0x3f, ++ 0xfa, 0xf0, 0x8a, 0x09, 0x6f, 0xba, 0x4e, 0x53, 0xf7, 0xfa, 0x4f, 0x20, ++ 0xa3, 0xf4, 0x4a, 0x5a, 0xde, 0x17, 0x1c, 0x29, 0x6a, 0x6f, 0x03, 0x48, ++ 0xdf, 0xad, 0x4f, 0xe4, 0xbc, 0x71, 0xc4, 0x72, 0x32, 0x11, 0x84, 0xac, ++ 0x09, 0xd2, 0x18, 0x44, 0x35, 0xf1, 0xcd, 0xaf, 0xa8, 0x98, 0xe0, 0x8b, ++ 0xec, 0xa0, 0x83, 0x37, 0xc3, 0x35, 0x85, 0xd6, 0xd8, 0x1b, 0xe0, 0x75, ++ 0xdc, 0xfd, 0xde, 0xc9, 0xeb, 0xd5, 0x18, 0x0f, 0xd3, 0x4c, 0x2f, 0x71, ++ 0xdc, 0x48, 0xe3, 0x14, 0xeb, 0xda, 0x00, 0x24, 0x24, 0x9e, 0xa3, 0x8e, ++ 0x3e, 0x08, 0x6f, 0x22, 0x24, 0xd6, 0xc4, 0x85, 0x8f, 0x68, 0x00, 0x4a, ++ 0x82, 0x4c, 0x33, 0x6e, 0xa5, 0x35, 0x7b, 0xeb, 0x4b, 0xdc, 0xa0, 0xa6, ++ 0x65, 0x6f, 0x5a, 0x7a, 0xdf, 0x8a, 0x01, 0x52, 0xa1, 0x6c, 0xff, 0x59, ++ 0x22, 0x7f, 0xe1, 0x96, 0x1b, 0x19, 0xb8, 0xf9, 0x5d, 0x44, 0x9f, 0x91, ++ 0x03, 0x3c, 0x3d, 0xa1, 0x2a, 0xb6, 0x5a, 0x51, 0xa0, 0xce, 0x4a, 0x88, ++ 0x22, 0x72, 0x9c, 0xdc, 0xc0, 0x47, 0x76, 0x35, 0x84, 0x75, 0x9b, 0x87, ++ 0x5c, 0xd3, 0xcf, 0xe7, 0xdd, 0xa3, 0x57, 0x14, 0xdf, 0x00, 0xfd, 0x19, ++ 0x2a, 0x7d, 0x89, 0x27, 0x1c, 0x78, 0x97, 0x04, 0x58, 0x48 ++}; ++unsigned int certificate2_der_len = 1366; ++ ++unsigned char hi_signed_2nd[] = { ++ 0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb1, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa2, 0x30, 0x82, ++ 0x02, 0x9e, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, ++ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02, ++ 0x7b, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 0x3a, ++ 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x47, ++ 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 0x74, ++ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, ++ 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, ++ 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 0x14, ++ 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 0x07, ++ 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 0x06, ++ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, ++ 0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 0x90, ++ 0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 0x99, ++ 0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 0x07, ++ 0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 0xfe, ++ 0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 0x5f, ++ 0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 0x4f, ++ 0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 0x6f, ++ 0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 0x53, ++ 0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 0xd2, ++ 0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 0xc0, ++ 0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 0xdf, ++ 0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 0x05, ++ 0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 0x3d, ++ 0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 0x7d, ++ 0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 0x81, ++ 0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 0x36, ++ 0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 0xd5, ++ 0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 0xcc, ++ 0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 0x70, ++ 0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 0x94, ++ 0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 0xe3, ++ 0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 0x20, ++ 0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 0xc2, ++ 0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 0xac, ++ 0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 0xdb, ++ 0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 0x49, ++ 0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 0xb0, ++ 0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 0xcb, ++ 0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 0x76, ++ 0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 0xa5, ++ 0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 0x49, ++ 0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 0x6b, ++ 0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 0x25, ++ 0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 0x2e, ++ 0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 0xa0, ++ 0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 0x98, ++ 0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 0x8b, ++ 0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 0x83, ++ 0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 0x3e, ++ 0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 0x8a, ++ 0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 0xb7, ++ 0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 0x26, ++ 0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 0xac, ++ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xb5, ++ 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, ++ 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, ++ 0x65, 0x64, 0x7e, 0x0a ++}; ++unsigned int hi_signed_2nd_len = 736; ++ ++unsigned char certificate_printable_der[] = { ++ 0x30, 0x82, 0x03, 0x39, 0x30, 0x82, 0x02, 0x21, 0xa0, 0x03, 0x02, 0x01, ++ 0x02, 0x02, 0x09, 0x00, 0xde, 0xf6, 0x22, 0xc4, 0xf2, 0xf1, 0x86, 0x02, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x0b, 0x05, 0x00, 0x30, 0x2a, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, ++ 0x04, 0x03, 0x13, 0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, ++ 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, ++ 0x43, 0x41, 0x20, 0x32, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 0x30, ++ 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x30, 0x33, 0x31, 0x31, 0x34, 0x31, ++ 0x39, 0x32, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x37, 0x31, 0x30, 0x32, 0x35, ++ 0x31, 0x34, 0x31, 0x39, 0x32, 0x33, 0x5a, 0x30, 0x2f, 0x31, 0x2d, 0x30, ++ 0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x24, 0x52, 0x65, 0x64, 0x20, ++ 0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, ++ 0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, ++ 0x33, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 0x30, 0x82, 0x01, 0x22, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, ++ 0x02, 0x82, 0x01, 0x01, 0x00, 0xbd, 0xda, 0xa1, 0xed, 0x8d, 0x8e, 0x15, ++ 0x5c, 0xf8, 0x01, 0x77, 0x48, 0x4a, 0x60, 0x96, 0xf9, 0x27, 0xfa, 0xe2, ++ 0xb1, 0x69, 0x0f, 0x51, 0x19, 0x52, 0x7e, 0xc4, 0x34, 0x8e, 0xe1, 0x9b, ++ 0x9c, 0xa4, 0xb1, 0x5c, 0xd6, 0x81, 0x98, 0x78, 0xfe, 0xa9, 0xe5, 0x0b, ++ 0x00, 0xba, 0x9c, 0x64, 0x7e, 0xc7, 0xcc, 0x72, 0xb1, 0x73, 0x4b, 0x11, ++ 0x07, 0x52, 0xf0, 0x20, 0x96, 0x8b, 0x99, 0x39, 0xde, 0xdb, 0xfa, 0x3d, ++ 0x45, 0xe2, 0x98, 0x7b, 0x0c, 0x41, 0xe4, 0x0c, 0xb5, 0x5d, 0x92, 0x74, ++ 0x39, 0x96, 0xe1, 0x97, 0x97, 0xa1, 0xad, 0x2e, 0xcc, 0xd0, 0x1b, 0x4d, ++ 0x9d, 0xbd, 0x3e, 0xa9, 0x36, 0x8e, 0xcc, 0xc7, 0x5f, 0x6a, 0x7d, 0x39, ++ 0x5e, 0x0b, 0x8d, 0xca, 0xe4, 0x83, 0xe9, 0x3b, 0x5c, 0x86, 0x47, 0xd4, ++ 0xba, 0x7d, 0x98, 0x26, 0xa1, 0xf4, 0xe8, 0x90, 0x6b, 0x0f, 0xf1, 0x6b, ++ 0x8c, 0xe3, 0xa2, 0x80, 0x3c, 0x96, 0xf1, 0x0a, 0xb6, 0x66, 0xc0, 0x4b, ++ 0x61, 0xf7, 0x74, 0xcd, 0xd3, 0x7b, 0x8e, 0x5e, 0x39, 0xda, 0x99, 0x20, ++ 0x33, 0x93, 0xd3, 0xf0, 0x7f, 0xad, 0x35, 0xe9, 0x88, 0x8d, 0x9c, 0xbf, ++ 0x65, 0xf1, 0x47, 0x02, 0xf9, 0x7c, 0xed, 0x27, 0x5f, 0x4a, 0x65, 0x3c, ++ 0xcf, 0x5f, 0x0e, 0x88, 0x95, 0x74, 0xde, 0xfb, 0x9e, 0x2e, 0x91, 0x9b, ++ 0x45, 0x37, 0xc8, 0x85, 0xff, 0xe3, 0x41, 0x70, 0xfe, 0xd5, 0xef, 0x0e, ++ 0x82, 0x22, 0x08, 0xb7, 0x3b, 0x44, 0x3e, 0xdc, 0x5b, 0x7f, 0xba, 0xbf, ++ 0xe6, 0x58, 0x9d, 0x02, 0x6e, 0x75, 0xbf, 0x50, 0xec, 0xcf, 0x3f, 0xa5, ++ 0x91, 0x0a, 0xe2, 0x59, 0x2c, 0xc3, 0xe7, 0x05, 0x03, 0xe8, 0xf2, 0x6f, ++ 0x2a, 0x04, 0x68, 0x9a, 0x31, 0x32, 0x8f, 0x04, 0x35, 0xcd, 0x1f, 0x34, ++ 0xcc, 0x4f, 0x79, 0x5a, 0x99, 0x8d, 0x9d, 0x5c, 0xf5, 0x02, 0x03, 0x01, ++ 0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, ++ 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03, ++ 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x1d, 0x06, ++ 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x65, 0xc5, 0xbe, 0xca, ++ 0xe6, 0x59, 0x6a, 0xfd, 0x6c, 0x71, 0xc4, 0xa7, 0x98, 0xc6, 0x25, 0x8d, ++ 0x7b, 0x67, 0x05, 0xd0, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, ++ 0x18, 0x30, 0x16, 0x80, 0x14, 0x81, 0xf8, 0xee, 0x47, 0x5c, 0x3e, 0xed, ++ 0xfb, 0xce, 0xa5, 0x84, 0xbe, 0xd7, 0xae, 0xdb, 0xd3, 0x7d, 0x64, 0xb3, ++ 0x2a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, ++ 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x66, 0x1e, 0x3d, ++ 0x1d, 0x53, 0x33, 0xde, 0x4e, 0xc7, 0xc4, 0xf4, 0xdf, 0xda, 0x18, 0x19, ++ 0x8a, 0xa9, 0xff, 0xe2, 0x63, 0x2b, 0xbe, 0xf2, 0x61, 0x63, 0xe2, 0xf6, ++ 0xed, 0x47, 0x1a, 0x71, 0x02, 0xec, 0x2a, 0xef, 0x89, 0x77, 0xe3, 0xfd, ++ 0x86, 0x69, 0xf1, 0x3f, 0x0d, 0xf9, 0x6e, 0xf9, 0x3b, 0xad, 0x26, 0x47, ++ 0xb7, 0xf2, 0x0d, 0xad, 0x23, 0xa3, 0x67, 0x3b, 0xcb, 0x6d, 0x9e, 0x03, ++ 0x0f, 0xbc, 0x69, 0x73, 0x9f, 0xd4, 0xa5, 0x0f, 0x6f, 0xf8, 0xab, 0x4d, ++ 0x36, 0xd1, 0xe0, 0xe0, 0x5d, 0x20, 0x43, 0x90, 0xc4, 0x65, 0x61, 0x93, ++ 0xe2, 0x0f, 0x51, 0x59, 0x0a, 0xf7, 0x88, 0x70, 0x57, 0xb9, 0x04, 0xa9, ++ 0x32, 0x57, 0x9c, 0xb3, 0x57, 0x38, 0x8b, 0x8e, 0x46, 0xc8, 0x32, 0x6c, ++ 0xb4, 0xf3, 0x96, 0x7f, 0x4b, 0xf0, 0x88, 0xf9, 0x7f, 0xe2, 0x71, 0xe1, ++ 0x8b, 0xe2, 0x14, 0xf1, 0x4b, 0x25, 0x00, 0x48, 0x1c, 0x7e, 0xe5, 0x8d, ++ 0x65, 0x2d, 0xeb, 0x72, 0x4f, 0x92, 0x44, 0xf3, 0xe6, 0xe0, 0xd0, 0xdf, ++ 0x85, 0xa8, 0x13, 0x4a, 0xfb, 0x99, 0xca, 0x14, 0x2c, 0x97, 0x80, 0x93, ++ 0x27, 0xd3, 0x20, 0xf8, 0x6d, 0x29, 0x28, 0x2c, 0xb9, 0x77, 0xea, 0xb1, ++ 0x63, 0xbd, 0x7d, 0x53, 0xfd, 0x4a, 0x62, 0x64, 0x0b, 0x98, 0xa8, 0xae, ++ 0x11, 0xfc, 0x6e, 0x8d, 0x63, 0xd4, 0x15, 0x55, 0xc6, 0x4c, 0x74, 0xf5, ++ 0x5f, 0xa0, 0xb9, 0x2c, 0x2d, 0x9a, 0x7a, 0x87, 0x6e, 0xf0, 0x5e, 0x25, ++ 0xed, 0xfc, 0xd8, 0xc4, 0x34, 0x33, 0x32, 0xad, 0x01, 0xd4, 0x4b, 0x49, ++ 0x51, 0xc2, 0x07, 0x7f, 0x90, 0x6d, 0xea, 0xf5, 0x4c, 0x41, 0x71, 0x64, ++ 0xeb, 0x1f, 0x29, 0xa3, 0x1f, 0x64, 0xa2, 0x1e, 0x0e, 0x6f, 0xa1, 0x67, ++ 0x99, 0x8d, 0x98, 0x1c, 0xb8, 0x53, 0x9d, 0x30, 0x1d, 0xae, 0x32, 0x56, ++ 0xd2 ++}; ++unsigned int certificate_printable_der_len = 829; ++ ++unsigned char certificate_eku_der[] = { ++ 0x30, 0x82, 0x03, 0x90, 0x30, 0x82, 0x02, 0x78, 0xa0, 0x03, 0x02, 0x01, ++ 0x02, 0x02, 0x09, 0x00, 0xd3, 0x9c, 0x41, 0x33, 0xdd, 0x6b, 0x5f, 0x45, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x0b, 0x05, 0x00, 0x30, 0x47, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, ++ 0x04, 0x03, 0x0c, 0x18, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, ++ 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, ++ 0x43, 0x41, 0x20, 0x36, 0x31, 0x22, 0x30, 0x20, 0x06, 0x09, 0x2a, 0x86, ++ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x13, 0x73, 0x65, 0x63, ++ 0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65, 0x64, 0x68, 0x61, 0x74, ++ 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x32, ++ 0x31, 0x35, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a, 0x17, 0x0d, 0x33, ++ 0x38, 0x30, 0x31, 0x31, 0x37, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a, ++ 0x30, 0x4e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, ++ 0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63, ++ 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67, ++ 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x36, 0x30, 0x32, 0x31, 0x22, 0x30, 0x20, ++ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, ++ 0x13, 0x73, 0x65, 0x63, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65, ++ 0x64, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, ++ 0x02, 0x82, 0x01, 0x01, 0x00, 0xaa, 0x6f, 0xbb, 0x92, 0x77, 0xd7, 0x15, ++ 0xef, 0x88, 0x80, 0x88, 0xc0, 0xe7, 0x89, 0xeb, 0x35, 0x76, 0xf4, 0x85, ++ 0x05, 0x0f, 0x19, 0xe4, 0x5f, 0x25, 0xdd, 0xc1, 0xa2, 0xe5, 0x5c, 0x06, ++ 0xfb, 0xf1, 0x06, 0xb5, 0x65, 0x45, 0xcb, 0xbd, 0x19, 0x33, 0x54, 0xb5, ++ 0x1a, 0xcd, 0xe4, 0xa8, 0x35, 0x2a, 0xfe, 0x9c, 0x53, 0xf4, 0xc6, 0x76, ++ 0xdb, 0x1f, 0x8a, 0xd4, 0x7b, 0x18, 0x11, 0xaf, 0xa3, 0x90, 0xd4, 0xdd, ++ 0x4d, 0xd5, 0x42, 0xcc, 0x14, 0x9a, 0x64, 0x6b, 0xc0, 0x7f, 0xaa, 0x1c, ++ 0x94, 0x47, 0x4d, 0x79, 0xbd, 0x57, 0x9a, 0xbf, 0x99, 0x4e, 0x96, 0xa9, ++ 0x31, 0x2c, 0xa9, 0xe7, 0x14, 0x65, 0x86, 0xc8, 0xac, 0x79, 0x5e, 0x78, ++ 0xa4, 0x3c, 0x00, 0x24, 0xd3, 0xf7, 0xe1, 0xf5, 0x12, 0xad, 0xa0, 0x29, ++ 0xe5, 0xfe, 0x80, 0xae, 0xf8, 0xaa, 0x60, 0x36, 0xe7, 0xe8, 0x94, 0xcb, ++ 0xe9, 0xd1, 0xcc, 0x0b, 0x4d, 0xf7, 0xde, 0xeb, 0x52, 0xd2, 0x73, 0x09, ++ 0x28, 0xdf, 0x48, 0x99, 0x53, 0x9f, 0xc5, 0x9a, 0xd4, 0x36, 0xa3, 0xc6, ++ 0x5e, 0x8d, 0xbe, 0xd5, 0xdc, 0x76, 0xb4, 0x74, 0xb8, 0x26, 0x18, 0x27, ++ 0xfb, 0xf2, 0xfb, 0xd0, 0x9b, 0x3d, 0x7f, 0x10, 0xe2, 0xab, 0x44, 0xc7, ++ 0x88, 0x7f, 0xb4, 0x3d, 0x3e, 0xa3, 0xff, 0x6d, 0x06, 0x4b, 0x3e, 0x55, ++ 0xb2, 0x84, 0xf4, 0xad, 0x54, 0x88, 0x81, 0xc3, 0x9c, 0xf8, 0xb6, 0x68, ++ 0x96, 0x38, 0x8b, 0xcd, 0x90, 0x6d, 0x25, 0x4b, 0xbf, 0x0c, 0x44, 0x90, ++ 0xa5, 0x5b, 0x98, 0xd0, 0x40, 0x2f, 0xbb, 0x0d, 0xa8, 0x4b, 0x8a, 0x62, ++ 0x82, 0x46, 0x46, 0x18, 0x38, 0xae, 0x82, 0x07, 0xd0, 0xb4, 0x2f, 0x16, ++ 0x79, 0x55, 0x9f, 0x1b, 0xc5, 0x08, 0x6d, 0x85, 0xdf, 0x3f, 0xa9, 0x9b, ++ 0x4b, 0xc6, 0x28, 0xd3, 0x58, 0x72, 0x3d, 0x37, 0x11, 0x02, 0x03, 0x01, ++ 0x00, 0x01, 0xa3, 0x78, 0x30, 0x76, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, ++ 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03, ++ 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, ++ 0x30, 0x16, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 0x0c, ++ 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03, ++ 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x6c, ++ 0xe4, 0x6c, 0x27, 0xaa, 0xcd, 0x0d, 0x4b, 0x74, 0x21, 0xa4, 0xf6, 0x5f, ++ 0x87, 0xb5, 0x31, 0xfe, 0x10, 0xbb, 0xa7, 0x30, 0x1f, 0x06, 0x03, 0x55, ++ 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe8, 0x6a, 0x1c, 0xab, ++ 0x2c, 0x48, 0xf9, 0x60, 0x36, 0xa2, 0xf0, 0x7b, 0x8e, 0xd2, 0x9d, 0xb4, ++ 0x2a, 0x28, 0x98, 0xc8, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, ++ 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, ++ 0x55, 0x34, 0xe2, 0xfa, 0xf6, 0x89, 0x86, 0xad, 0x92, 0x21, 0xec, 0xb9, ++ 0x54, 0x0e, 0x18, 0x47, 0x0d, 0x1b, 0xa7, 0x58, 0xad, 0x69, 0xe4, 0xef, ++ 0x3b, 0xe6, 0x8d, 0xdd, 0xda, 0x0c, 0x45, 0xf6, 0xe8, 0x96, 0xa4, 0x29, ++ 0x0f, 0xbb, 0xcf, 0x16, 0xae, 0x93, 0xd0, 0xcb, 0x2a, 0x26, 0x1a, 0x7b, ++ 0xfc, 0x51, 0x22, 0x76, 0x98, 0x31, 0xa7, 0x0f, 0x29, 0x35, 0x79, 0xbf, ++ 0xe2, 0x4f, 0x0f, 0x14, 0xf5, 0x1f, 0xcb, 0xbf, 0x87, 0x65, 0x13, 0x32, ++ 0xa3, 0x19, 0x4a, 0xd1, 0x3f, 0x45, 0xd4, 0x4b, 0xe2, 0x00, 0x26, 0xa9, ++ 0x3e, 0xd7, 0xa5, 0x37, 0x9f, 0xf5, 0xad, 0x61, 0xe2, 0x40, 0xa9, 0x74, ++ 0x24, 0x53, 0xf2, 0x78, 0xeb, 0x10, 0x9b, 0x2c, 0x27, 0x88, 0x46, 0xcb, ++ 0xe4, 0x60, 0xca, 0xf5, 0x06, 0x24, 0x40, 0x2a, 0x97, 0x3a, 0xcc, 0xd0, ++ 0x81, 0xb1, 0x15, 0xa3, 0x4f, 0xd0, 0x2b, 0x4f, 0xca, 0x6e, 0xaa, 0x24, ++ 0x31, 0xb3, 0xac, 0xa6, 0x75, 0x05, 0xfe, 0x8a, 0xf4, 0x41, 0xc4, 0x06, ++ 0x8a, 0xc7, 0x0a, 0x83, 0x4e, 0x49, 0xd4, 0x3f, 0x83, 0x50, 0xec, 0x57, ++ 0x04, 0x97, 0x14, 0x49, 0xf5, 0xe1, 0xb1, 0x7a, 0x9c, 0x09, 0x4f, 0x61, ++ 0x87, 0xc3, 0x97, 0x22, 0x17, 0xc2, 0xeb, 0xcc, 0x32, 0x81, 0x31, 0x21, ++ 0x3f, 0x10, 0x57, 0x5b, 0x43, 0xbe, 0xcd, 0x68, 0x82, 0xbe, 0xe5, 0xc1, ++ 0x65, 0x94, 0x7e, 0xc2, 0x34, 0x76, 0x2b, 0xcf, 0x89, 0x3c, 0x2b, 0x81, ++ 0x23, 0x72, 0x95, 0xcf, 0xc9, 0x67, 0x19, 0x2a, 0xd5, 0x5c, 0xca, 0xa3, ++ 0x46, 0xbd, 0x48, 0x06, 0x0b, 0xa6, 0xa3, 0x96, 0x50, 0x28, 0xc7, 0x7e, ++ 0xcf, 0x62, 0xf2, 0xfa, 0xc4, 0xf2, 0x53, 0xe3, 0xc9, 0xe8, 0x2e, 0xdd, ++ 0x29, 0x37, 0x07, 0x47, 0xff, 0xff, 0x8a, 0x32, 0xbd, 0xa2, 0xb7, 0x21, ++ 0x89, 0xa0, 0x55, 0xf7 ++}; ++unsigned int certificate_eku_der_len = 916; +diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c +index 96781fb39..403fa5c78 100644 +--- a/grub-core/tests/lib/functional_test.c ++++ b/grub-core/tests/lib/functional_test.c +@@ -73,6 +73,7 @@ grub_functional_all_tests (grub_extcmd_context_t ctxt __attribute__ ((unused)), + grub_dl_load ("xnu_uuid_test"); + grub_dl_load ("pbkdf2_test"); + grub_dl_load ("signature_test"); ++ grub_dl_load ("appended_signature_test"); + grub_dl_load ("sleep_test"); + grub_dl_load ("bswap_test"); + grub_dl_load ("ctz_test"); +diff --git a/grub-core/video/ieee1275.c b/grub-core/video/ieee1275.c +index ca3d3c3b2..5592e4bb7 100644 +--- a/grub-core/video/ieee1275.c ++++ b/grub-core/video/ieee1275.c +@@ -351,9 +351,12 @@ static struct grub_video_adapter grub_video_ieee1275_adapter = + + GRUB_MOD_INIT(ieee1275_fb) + { +- find_display (); +- if (display) +- grub_video_register (&grub_video_ieee1275_adapter); ++ if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT)) ++ { ++ find_display (); ++ if (display) ++ grub_video_register (&grub_video_ieee1275_adapter); ++ } + } + + GRUB_MOD_FINI(ieee1275_fb) +diff --git a/include/grub/arm/efi/console.h b/include/grub/arm/efi/console.h +new file mode 100644 +index 000000000..1592f6f76 +--- /dev/null ++++ b/include/grub/arm/efi/console.h +@@ -0,0 +1,24 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_ARM_EFI_CONSOLE_H ++#define GRUB_ARM_EFI_CONSOLE_H ++ ++#include ++ ++#endif /* ! GRUB_ARM_EFI_CONSOLE_H */ +diff --git a/include/grub/arm/efi/memory.h b/include/grub/arm/efi/memory.h +index 2c64918e3..a4c2ec835 100644 +--- a/include/grub/arm/efi/memory.h ++++ b/include/grub/arm/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/arm64/efi/console.h b/include/grub/arm64/efi/console.h +new file mode 100644 +index 000000000..956893393 +--- /dev/null ++++ b/include/grub/arm64/efi/console.h +@@ -0,0 +1,24 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_ARM64_EFI_CONSOLE_H ++#define GRUB_ARM64_EFI_CONSOLE_H ++ ++#include ++ ++#endif /* ! GRUB_ARM64_EFI_CONSOLE_H */ +diff --git a/include/grub/arm64/efi/memory.h b/include/grub/arm64/efi/memory.h +index c6cb32417..acb61dca4 100644 +--- a/include/grub/arm64/efi/memory.h ++++ b/include/grub/arm64/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h +index bcb4d9ba7..9414dc1b9 100644 +--- a/include/grub/at_keyboard.h ++++ b/include/grub/at_keyboard.h +@@ -19,6 +19,10 @@ + #ifndef GRUB_AT_KEYBOARD_HEADER + #define GRUB_AT_KEYBOARD_HEADER 1 + ++/* ++ * Refer to https://wiki.osdev.org/%228042%22_PS/2_Controller for details. ++ */ ++ + /* Used for sending commands to the controller. */ + #define KEYBOARD_COMMAND_ISREADY(x) !((x) & 0x02) + #define KEYBOARD_COMMAND_READ 0x20 +diff --git a/include/grub/backtrace.h b/include/grub/backtrace.h +index 395519762..275cf85e2 100644 +--- a/include/grub/backtrace.h ++++ b/include/grub/backtrace.h +@@ -19,8 +19,14 @@ + #ifndef GRUB_BACKTRACE_HEADER + #define GRUB_BACKTRACE_HEADER 1 + +-void grub_backtrace (void); +-void grub_backtrace_pointer (void *ptr); ++#include ++#include ++ ++void EXPORT_FUNC(grub_debug_backtrace) (const char * const debug, ++ unsigned int skip); ++void EXPORT_FUNC(grub_backtrace) (unsigned int skip); ++void grub_backtrace_arch (unsigned int skip); ++void grub_backtrace_pointer (void *ptr, unsigned int skip); + void grub_backtrace_print_address (void *addr); + + #endif +diff --git a/include/grub/btrfs.h b/include/grub/btrfs.h +index 9d93fb6c1..234ad9767 100644 +--- a/include/grub/btrfs.h ++++ b/include/grub/btrfs.h +@@ -29,6 +29,7 @@ enum + GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM = 0x84, + GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF = 0x90, + GRUB_BTRFS_ITEM_TYPE_DEVICE = 0xd8, ++ GRUB_BTRFS_ITEM_TYPE_ROOT_REF = 0x9c, + GRUB_BTRFS_ITEM_TYPE_CHUNK = 0xe4 + }; + +diff --git a/include/grub/compiler.h b/include/grub/compiler.h +index 0c5519387..441a9eca0 100644 +--- a/include/grub/compiler.h ++++ b/include/grub/compiler.h +@@ -56,4 +56,6 @@ + # define CLANG_PREREQ(maj,min) 0 + #endif + ++#define UNUSED __attribute__((__unused__)) ++ + #endif /* ! GRUB_COMPILER_HEADER */ +diff --git a/include/grub/dl.h b/include/grub/dl.h +index cd1f46c8b..1e1262a28 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #endif + + /* +@@ -54,6 +55,7 @@ grub_mod_fini (void) + + #define GRUB_MOD_INIT(name) \ + static void grub_mod_init (grub_dl_t mod __attribute__ ((unused))) __attribute__ ((used)); \ ++extern void grub_##name##_init (void); \ + void \ + grub_##name##_init (void) { grub_mod_init (0); } \ + static void \ +@@ -61,6 +63,7 @@ grub_mod_init (grub_dl_t mod __attribute__ ((unused))) + + #define GRUB_MOD_FINI(name) \ + static void grub_mod_fini (void) __attribute__ ((used)); \ ++extern void grub_##name##_fini (void); \ + void \ + grub_##name##_fini (void) { grub_mod_fini (); } \ + static void \ +@@ -119,7 +122,7 @@ grub_mod_fini (void) + #define ATTRIBUTE_USED __unused__ + #endif + #define GRUB_MOD_LICENSE(license) \ +- static char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license; ++ static const char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license; + #define GRUB_MOD_DEP(name) \ + static const char grub_module_depend_##name[] \ + __attribute__((section(GRUB_MOD_SECTION(moddeps)), ATTRIBUTE_USED)) = #name +@@ -242,11 +245,22 @@ grub_dl_get (const char *name) + return 0; + } + ++#ifdef GRUB_MACHINE_EMU ++/* ++ * Under grub-emu, modules are faked and NULL is passed to GRUB_MOD_INIT. ++ * So we fake this out to avoid a NULL deref. ++ */ ++static inline void ++grub_dl_set_persistent (grub_dl_t mod __attribute__((unused))) ++{ ++} ++#else + static inline void + grub_dl_set_persistent (grub_dl_t mod) + { + mod->persistent = 1; + } ++#endif + + static inline int + grub_dl_is_persistent (grub_dl_t mod) +@@ -254,8 +268,53 @@ grub_dl_is_persistent (grub_dl_t mod) + return mod->persistent; + } + ++static inline const char * ++grub_dl_get_section_name (const Elf_Ehdr *e, const Elf_Shdr *s) ++{ ++ Elf_Shdr *str_s; ++ const char *str; ++ ++ str_s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); ++ str = (char *) e + str_s->sh_offset; ++ ++ return str + s->sh_name; ++} ++ ++static inline long ++grub_dl_find_section_index (Elf_Ehdr *e, const char *name) ++{ ++ Elf_Shdr *s; ++ const char *str; ++ unsigned i; ++ ++ s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); ++ str = (char *) e + s->sh_offset; ++ ++ for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); ++ i < e->e_shnum; ++ i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) ++ if (grub_strcmp (str + s->sh_name, name) == 0) ++ return (long)i; ++ return -1; ++} ++ ++/* Return the segment for a section of index N */ ++static inline grub_dl_segment_t ++grub_dl_find_segment (grub_dl_t mod, unsigned n) ++{ ++ grub_dl_segment_t seg; ++ ++ for (seg = mod->segment; seg; seg = seg->next) ++ if (seg->section == n) ++ return seg; ++ ++ return NULL; ++} ++ + #endif + ++void * EXPORT_FUNC(grub_resolve_symbol) (const char *name); ++const char * EXPORT_FUNC(grub_get_symbol_by_addr) (const void *addr, int isfunc); + grub_err_t grub_dl_register_symbol (const char *name, void *addr, + int isfunc, grub_dl_t mod); + +@@ -264,6 +323,8 @@ grub_err_t grub_arch_dl_check_header (void *ehdr); + grub_err_t + grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + Elf_Shdr *s, grub_dl_segment_t seg); ++grub_size_t ++grub_arch_dl_min_alignment (void); + #endif + + #if defined (_mips) +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index d44d00ad7..5047ecf28 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -369,6 +369,16 @@ + { 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \ + } + ++#define GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID \ ++ { 0x5b446ed1, 0xe30b, 0x4faa, \ ++ { 0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \ ++ } ++ ++#define GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID \ ++ { 0x937fe521, 0x95ae, 0x4d1a, \ ++ { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \ ++ } ++ + #define LINUX_EFI_INITRD_MEDIA_GUID \ + { 0x5568e427, 0x68fc, 0x4f3d, \ + { 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68 } \ +@@ -379,6 +389,11 @@ + {0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } \ + } + ++#define GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID \ ++ { 0xf4560cf6, 0x40ec, 0x4b4a, \ ++ { 0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89 } \ ++ } ++ + struct grub_efi_sal_system_table + { + grub_uint32_t signature; +@@ -577,7 +592,16 @@ typedef grub_uint64_t grub_efi_uint64_t; + typedef grub_uint8_t grub_efi_char8_t; + typedef grub_uint16_t grub_efi_char16_t; + ++ + typedef grub_efi_uintn_t grub_efi_status_t; ++/* Make grub_efi_status_t reasonably printable. */ ++#if GRUB_CPU_SIZEOF_VOID_P == 8 ++#define PRIxGRUB_EFI_STATUS "lx" ++#define PRIdGRUB_EFI_STATUS "ld" ++#else ++#define PRIxGRUB_EFI_STATUS "llx" ++#define PRIdGRUB_EFI_STATUS "lld" ++#endif + + /* + * On x86, the EFI calling convention may deviate from the local one, so +@@ -637,12 +661,35 @@ typedef void *grub_efi_handle_t; + typedef void *grub_efi_event_t; + typedef grub_efi_uint64_t grub_efi_lba_t; + typedef grub_efi_uintn_t grub_efi_tpl_t; +-typedef grub_uint8_t grub_efi_mac_address_t[32]; +-typedef grub_uint8_t grub_efi_ipv4_address_t[4]; +-typedef grub_uint16_t grub_efi_ipv6_address_t[8]; +-typedef grub_uint8_t grub_efi_ip_address_t[8] __attribute__ ((aligned(4))); ++typedef grub_efi_uint8_t grub_efi_mac_address_t[32]; ++typedef grub_efi_uint8_t grub_efi_ipv4_address_t[4]; ++typedef grub_efi_uint8_t grub_efi_ipv6_address_t[16]; ++typedef union ++{ ++ grub_efi_uint32_t addr[4]; ++ grub_efi_ipv4_address_t v4; ++ grub_efi_ipv6_address_t v6; ++} grub_efi_ip_address_t __attribute__ ((aligned(4))); ++ + typedef grub_efi_uint64_t grub_efi_physical_address_t; + typedef grub_efi_uint64_t grub_efi_virtual_address_t; ++typedef struct { ++ grub_uint8_t addr[4]; ++} grub_efi_pxe_ipv4_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[16]; ++} grub_efi_pxe_ipv6_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[32]; ++} grub_efi_pxe_mac_address_t; ++ ++typedef union { ++ grub_uint32_t addr[4]; ++ grub_efi_pxe_ipv4_address_t v4; ++ grub_efi_pxe_ipv6_address_t v6; ++} grub_efi_pxe_ip_address_t; + + /* XXX although the spec does not specify the padding, this actually + must have the padding! */ +@@ -876,6 +923,8 @@ struct grub_efi_ipv4_device_path + grub_efi_uint16_t remote_port; + grub_efi_uint16_t protocol; + grub_efi_uint8_t static_ip_address; ++ grub_efi_ipv4_address_t gateway_ip_address; ++ grub_efi_ipv4_address_t subnet_mask; + } GRUB_PACKED; + typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t; + +@@ -890,6 +939,8 @@ struct grub_efi_ipv6_device_path + grub_efi_uint16_t remote_port; + grub_efi_uint16_t protocol; + grub_efi_uint8_t static_ip_address; ++ grub_efi_uint8_t prefix_length; ++ grub_efi_ipv6_address_t gateway_ip_address; + } GRUB_PACKED; + typedef struct grub_efi_ipv6_device_path grub_efi_ipv6_device_path_t; + +@@ -939,6 +990,24 @@ struct grub_efi_vlan_device_path + } GRUB_PACKED; + typedef struct grub_efi_vlan_device_path grub_efi_vlan_device_path_t; + ++#define GRUB_EFI_URI_DEVICE_PATH_SUBTYPE 24 ++ ++struct grub_efi_uri_device_path ++{ ++ grub_efi_device_path_t header; ++ grub_efi_uint8_t uri[0]; ++} GRUB_PACKED; ++typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t; ++ ++#define GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE 31 ++struct grub_efi_dns_device_path ++{ ++ grub_efi_device_path_t header; ++ grub_efi_uint8_t is_ipv6; ++ grub_efi_pxe_ip_address_t dns_server_ip[0]; ++} GRUB_PACKED; ++typedef struct grub_efi_dns_device_path grub_efi_dns_device_path_t; ++ + #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10 + + /* Media Device Path. */ +@@ -1021,6 +1090,23 @@ struct grub_efi_bios_device_path + } GRUB_PACKED; + typedef struct grub_efi_bios_device_path grub_efi_bios_device_path_t; + ++/* Service Binding definitions */ ++struct grub_efi_service_binding; ++ ++typedef grub_efi_status_t ++(__grub_efi_api *grub_efi_service_binding_create_child) (struct grub_efi_service_binding *this, ++ grub_efi_handle_t *child_handle); ++ ++typedef grub_efi_status_t ++(__grub_efi_api *grub_efi_service_binding_destroy_child) (struct grub_efi_service_binding *this, ++ grub_efi_handle_t *child_handle); ++ ++typedef struct grub_efi_service_binding ++{ ++ grub_efi_service_binding_create_child create_child; ++ grub_efi_service_binding_destroy_child destroy_child; ++} grub_efi_service_binding_t; ++ + struct grub_efi_open_protocol_information_entry + { + grub_efi_handle_t agent_handle; +@@ -1521,33 +1607,178 @@ struct grub_efi_simple_text_output_interface + }; + typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output_interface_t; + +-typedef grub_uint8_t grub_efi_pxe_packet_t[1472]; ++typedef struct grub_efi_pxe_dhcpv4_packet ++{ ++ grub_efi_uint8_t bootp_opcode; ++ grub_efi_uint8_t bootp_hwtype; ++ grub_efi_uint8_t bootp_hwaddr_len; ++ grub_efi_uint8_t bootp_gate_hops; ++ grub_efi_uint32_t bootp_ident; ++ grub_efi_uint16_t bootp_seconds; ++ grub_efi_uint16_t bootp_flags; ++ grub_efi_uint8_t bootp_ci_addr[4]; ++ grub_efi_uint8_t bootp_yi_addr[4]; ++ grub_efi_uint8_t bootp_si_addr[4]; ++ grub_efi_uint8_t bootp_gi_addr[4]; ++ grub_efi_uint8_t bootp_hw_addr[16]; ++ grub_efi_uint8_t bootp_srv_name[64]; ++ grub_efi_uint8_t bootp_boot_file[128]; ++ grub_efi_uint32_t dhcp_magik; ++ grub_efi_uint8_t dhcp_options[56]; ++} grub_efi_pxe_dhcpv4_packet_t; ++ ++struct grub_efi_pxe_dhcpv6_packet ++{ ++ grub_efi_uint32_t message_type:8; ++ grub_efi_uint32_t transaction_id:24; ++ grub_efi_uint8_t dhcp_options[1024]; ++} GRUB_PACKED; ++typedef struct grub_efi_pxe_dhcpv6_packet grub_efi_pxe_dhcpv6_packet_t; ++ ++typedef union ++{ ++ grub_efi_uint8_t raw[1472]; ++ grub_efi_pxe_dhcpv4_packet_t dhcpv4; ++ grub_efi_pxe_dhcpv6_packet_t dhcpv6; ++} grub_efi_pxe_packet_t; ++ ++typedef struct grub_efi_pxe_icmp_error ++{ ++ grub_efi_uint8_t type; ++ grub_efi_uint8_t code; ++ grub_efi_uint16_t checksum; ++ union ++ { ++ grub_efi_uint32_t reserved; ++ grub_efi_uint32_t mtu; ++ grub_efi_uint32_t pointer; ++ struct ++ { ++ grub_efi_uint16_t identifier; ++ grub_efi_uint16_t sequence; ++ } echo; ++ } u; ++ grub_efi_uint8_t data[494]; ++} grub_efi_pxe_icmp_error_t; ++ ++typedef struct grub_efi_pxe_tftp_error ++{ ++ grub_efi_uint8_t error_code; ++ grub_efi_char8_t error_string[127]; ++} grub_efi_pxe_tftp_error_t; ++ ++typedef grub_efi_uint16_t grub_efi_pxe_base_code_udp_port_t; ++ ++typedef enum { ++ GRUB_EFI_PXE_BASE_CODE_TFTP_FIRST, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_WRITE_FILE, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_FILE, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_LAST ++} grub_efi_pxe_base_code_tftp_opcode_t; ++ ++typedef struct { ++ grub_efi_ip_address_t mcast_ip; ++ grub_efi_pxe_base_code_udp_port_t c_port; ++ grub_efi_pxe_base_code_udp_port_t s_port; ++ grub_efi_uint16_t listen_timeout; ++ grub_efi_uint16_t transmit_timeout; ++} grub_efi_pxe_base_code_mtftp_info_t; ++ ++#define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8 ++typedef struct grub_efi_pxe_ip_filter ++{ ++ grub_efi_uint8_t filters; ++ grub_efi_uint8_t ip_count; ++ grub_efi_uint16_t reserved; ++ grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT]; ++} grub_efi_pxe_ip_filter_t; ++ ++typedef struct { ++ grub_efi_pxe_ip_address_t ip_addr; ++ grub_efi_pxe_mac_address_t mac_addr; ++} grub_efi_pxe_arp_entry_t; ++ ++typedef struct { ++ grub_efi_pxe_ip_address_t ip_addr; ++ grub_efi_pxe_ip_address_t subnet_mask; ++ grub_efi_pxe_ip_address_t gw_addr; ++} grub_efi_pxe_route_entry_t; ++ ++ ++#define GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8 ++#define GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8 + + typedef struct grub_efi_pxe_mode + { +- grub_uint8_t unused[52]; ++ grub_efi_boolean_t started; ++ grub_efi_boolean_t ipv6_available; ++ grub_efi_boolean_t ipv6_supported; ++ grub_efi_boolean_t using_ipv6; ++ grub_efi_boolean_t bis_supported; ++ grub_efi_boolean_t bis_detected; ++ grub_efi_boolean_t auto_arp; ++ grub_efi_boolean_t send_guid; ++ grub_efi_boolean_t dhcp_discover_valid; ++ grub_efi_boolean_t dhcp_ack_received; ++ grub_efi_boolean_t proxy_offer_received; ++ grub_efi_boolean_t pxe_discover_valid; ++ grub_efi_boolean_t pxe_reply_received; ++ grub_efi_boolean_t pxe_bis_reply_received; ++ grub_efi_boolean_t icmp_error_received; ++ grub_efi_boolean_t tftp_error_received; ++ grub_efi_boolean_t make_callbacks; ++ grub_efi_uint8_t ttl; ++ grub_efi_uint8_t tos; ++ grub_efi_ip_address_t station_ip; ++ grub_efi_ip_address_t subnet_mask; + grub_efi_pxe_packet_t dhcp_discover; + grub_efi_pxe_packet_t dhcp_ack; + grub_efi_pxe_packet_t proxy_offer; + grub_efi_pxe_packet_t pxe_discover; + grub_efi_pxe_packet_t pxe_reply; ++ grub_efi_pxe_packet_t pxe_bis_reply; ++ grub_efi_pxe_ip_filter_t ip_filter; ++ grub_efi_uint32_t arp_cache_entries; ++ grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES]; ++ grub_efi_uint32_t route_table_entries; ++ grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES]; ++ grub_efi_pxe_icmp_error_t icmp_error; ++ grub_efi_pxe_tftp_error_t tftp_error; + } grub_efi_pxe_mode_t; + + typedef struct grub_efi_pxe + { + grub_uint64_t rev; +- void *start; +- void *stop; +- void *dhcp; +- void *discover; +- void *mftp; +- void *udpwrite; +- void *udpread; +- void *setipfilter; +- void *arp; +- void *setparams; +- void *setstationip; +- void *setpackets; ++ grub_efi_status_t (__grub_efi_api *start) (struct grub_efi_pxe *this, grub_efi_boolean_t use_ipv6); ++ void (*stop) (void); ++ grub_efi_status_t (__grub_efi_api *dhcp) (struct grub_efi_pxe *this, ++ grub_efi_boolean_t sort_offers); ++ void (*discover) (void); ++ grub_efi_status_t (__grub_efi_api *mtftp) (struct grub_efi_pxe *this, ++ grub_efi_pxe_base_code_tftp_opcode_t operation, ++ void *buffer_ptr, ++ grub_efi_boolean_t overwrite, ++ grub_efi_uint64_t *buffer_size, ++ grub_efi_uintn_t *block_size, ++ grub_efi_pxe_ip_address_t *server_ip, ++ //grub_efi_ip_address_t *server_ip, ++ grub_efi_char8_t *filename, ++ grub_efi_pxe_base_code_mtftp_info_t *info, ++ grub_efi_boolean_t dont_use_buffer); ++ void (*udpwrite) (void); ++ void (*udpread) (void); ++ void (*setipfilter) (void); ++ void (*arp) (void); ++ void (*setparams) (void); ++ grub_efi_status_t (__grub_efi_api *set_station_ip) (struct grub_efi_pxe *this, ++ grub_efi_pxe_ip_address_t *new_station_ip, ++ grub_efi_pxe_ip_address_t *new_subnet_mask); ++ void (*setpackets) (void); + struct grub_efi_pxe_mode *mode; + } grub_efi_pxe_t; + +@@ -1775,6 +2006,8 @@ struct grub_efi_block_io + }; + typedef struct grub_efi_block_io grub_efi_block_io_t; + ++#define GRUB_MOK_POLICY_NX_REQUIRED 0x1 ++ + struct grub_efi_shim_lock_protocol + { + /* +@@ -1809,6 +2042,173 @@ struct grub_efi_load_file2 + }; + typedef struct grub_efi_load_file2 grub_efi_load_file2_t; + ++enum grub_efi_ip4_config2_data_type { ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MAXIMUM ++}; ++typedef enum grub_efi_ip4_config2_data_type grub_efi_ip4_config2_data_type_t; ++ ++struct grub_efi_ip4_config2_protocol ++{ ++ grub_efi_status_t (__grub_efi_api *set_data) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_uintn_t data_size, ++ void *data); ++ ++ grub_efi_status_t (__grub_efi_api *get_data) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_uintn_t *data_size, ++ void *data); ++ ++ grub_efi_status_t (__grub_efi_api *register_data_notify) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_event_t event); ++ ++ grub_efi_status_t (__grub_efi_api *unregister_datanotify) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_event_t event); ++}; ++typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t; ++ ++struct grub_efi_ip4_route_table { ++ grub_efi_ipv4_address_t subnet_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_ipv4_address_t gateway_address; ++}; ++ ++typedef struct grub_efi_ip4_route_table grub_efi_ip4_route_table_t; ++ ++#define GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32 ++ ++struct grub_efi_ip4_config2_interface_info { ++ grub_efi_char16_t name[GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE]; ++ grub_efi_uint8_t if_type; ++ grub_efi_uint32_t hw_address_size; ++ grub_efi_mac_address_t hw_address; ++ grub_efi_ipv4_address_t station_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_uint32_t route_table_size; ++ grub_efi_ip4_route_table_t *route_table; ++}; ++ ++typedef struct grub_efi_ip4_config2_interface_info grub_efi_ip4_config2_interface_info_t; ++ ++enum grub_efi_ip4_config2_policy { ++ GRUB_EFI_IP4_CONFIG2_POLICY_STATIC, ++ GRUB_EFI_IP4_CONFIG2_POLICY_DHCP, ++ GRUB_EFI_IP4_CONFIG2_POLICY_MAX ++}; ++ ++typedef enum grub_efi_ip4_config2_policy grub_efi_ip4_config2_policy_t; ++ ++struct grub_efi_ip4_config2_manual_address { ++ grub_efi_ipv4_address_t address; ++ grub_efi_ipv4_address_t subnet_mask; ++}; ++ ++typedef struct grub_efi_ip4_config2_manual_address grub_efi_ip4_config2_manual_address_t; ++ ++enum grub_efi_ip6_config_data_type { ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DUP_ADDR_DETECT_TRANSMITS, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MAXIMUM ++}; ++typedef enum grub_efi_ip6_config_data_type grub_efi_ip6_config_data_type_t; ++ ++struct grub_efi_ip6_config_protocol ++{ ++ grub_efi_status_t (__grub_efi_api *set_data) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_uintn_t data_size, ++ void *data); ++ ++ grub_efi_status_t (__grub_efi_api *get_data) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_uintn_t *data_size, ++ void *data); ++ ++ grub_efi_status_t (__grub_efi_api *register_data_notify) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_event_t event); ++ ++ grub_efi_status_t (__grub_efi_api *unregister_datanotify) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_event_t event); ++}; ++typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t; ++ ++enum grub_efi_ip6_config_policy { ++ GRUB_EFI_IP6_CONFIG_POLICY_MANUAL, ++ GRUB_EFI_IP6_CONFIG_POLICY_AUTOMATIC ++}; ++typedef enum grub_efi_ip6_config_policy grub_efi_ip6_config_policy_t; ++ ++struct grub_efi_ip6_address_info { ++ grub_efi_ipv6_address_t address; ++ grub_efi_uint8_t prefix_length; ++}; ++typedef struct grub_efi_ip6_address_info grub_efi_ip6_address_info_t; ++ ++struct grub_efi_ip6_route_table { ++ grub_efi_pxe_ipv6_address_t gateway; ++ grub_efi_pxe_ipv6_address_t destination; ++ grub_efi_uint8_t prefix_length; ++}; ++typedef struct grub_efi_ip6_route_table grub_efi_ip6_route_table_t; ++ ++struct grub_efi_ip6_config_interface_info { ++ grub_efi_char16_t name[32]; ++ grub_efi_uint8_t if_type; ++ grub_efi_uint32_t hw_address_size; ++ grub_efi_mac_address_t hw_address; ++ grub_efi_uint32_t address_info_count; ++ grub_efi_ip6_address_info_t *address_info; ++ grub_efi_uint32_t route_count; ++ grub_efi_ip6_route_table_t *route_table; ++}; ++typedef struct grub_efi_ip6_config_interface_info grub_efi_ip6_config_interface_info_t; ++ ++struct grub_efi_ip6_config_dup_addr_detect_transmits { ++ grub_efi_uint32_t dup_addr_detect_transmits; ++}; ++typedef struct grub_efi_ip6_config_dup_addr_detect_transmits grub_efi_ip6_config_dup_addr_detect_transmits_t; ++ ++struct grub_efi_ip6_config_manual_address { ++ grub_efi_ipv6_address_t address; ++ grub_efi_boolean_t is_anycast; ++ grub_efi_uint8_t prefix_length; ++}; ++typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t; ++ ++struct grub_efi_memory_attribute_protocol ++{ ++ grub_efi_status_t (__grub_efi_api *get_memory_attributes) ( ++ struct grub_efi_memory_attribute_protocol *this, ++ grub_efi_physical_address_t base_address, ++ grub_efi_uint64_t length, ++ grub_efi_uint64_t *attributes); ++ grub_efi_status_t (__grub_efi_api *set_memory_attributes) ( ++ struct grub_efi_memory_attribute_protocol *this, ++ grub_efi_physical_address_t base_address, ++ grub_efi_uint64_t length, ++ grub_efi_uint64_t attributes); ++ grub_efi_status_t (__grub_efi_api *clear_memory_attributes) ( ++ struct grub_efi_memory_attribute_protocol *this, ++ grub_efi_physical_address_t base_address, ++ grub_efi_uint64_t length, ++ grub_efi_uint64_t attributes); ++}; ++typedef struct grub_efi_memory_attribute_protocol grub_efi_memory_attribute_protocol_t; ++ + struct initrd_media_device_path { + grub_efi_vendor_media_device_path_t vendor; + grub_efi_device_path_t end; +diff --git a/include/grub/efi/debug.h b/include/grub/efi/debug.h +index c2d2a03b0..961e591af 100644 +--- a/include/grub/efi/debug.h ++++ b/include/grub/efi/debug.h +@@ -27,7 +27,7 @@ + void grub_efi_register_debug_commands (void); + + static inline void +-grub_efi_print_gdb_info (void) ++grub_efi_print_gdb_info (bool debug) + { + grub_addr_t text; + +@@ -35,7 +35,10 @@ grub_efi_print_gdb_info (void) + if (!text) + return; + +- grub_printf ("dynamic_load_symbols %p\n", (void *)text); ++ if (debug) ++ grub_qdprintf ("gdb", "dynamic_load_symbols %p\n", (void *)text); ++ else ++ grub_printf ("dynamic_load_symbols %p\n", (void *)text); + } + + #endif /* ! GRUB_EFI_DEBUG_HEADER */ +diff --git a/include/grub/efi/dhcp.h b/include/grub/efi/dhcp.h +new file mode 100644 +index 000000000..d996716e4 +--- /dev/null ++++ b/include/grub/efi/dhcp.h +@@ -0,0 +1,343 @@ ++#ifndef GRUB_EFI_DHCP_HEADER ++#define GRUB_EFI_DHCP_HEADER 1 ++ ++#define GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID \ ++ { 0x9d9a39d8, 0xbd42, 0x4a73, \ ++ { 0xa4, 0xd5, 0x8e, 0xe9, 0x4b, 0xe1, 0x13, 0x80 } \ ++ } ++ ++#define GRUB_EFI_DHCP4_PROTOCOL_GUID \ ++ { 0x8a219718, 0x4ef5, 0x4761, \ ++ { 0x91, 0xc8, 0xc0, 0xf0, 0x4b, 0xda, 0x9e, 0x56 } \ ++ } ++ ++#define GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID \ ++ { 0x9fb9a8a1, 0x2f4a, 0x43a6, \ ++ { 0x88, 0x9c, 0xd0, 0xf7, 0xb6, 0xc4 ,0x7a, 0xd5 } \ ++ } ++ ++#define GRUB_EFI_DHCP6_PROTOCOL_GUID \ ++ { 0x87c8bad7, 0x595, 0x4053, \ ++ { 0x82, 0x97, 0xde, 0xde, 0x39, 0x5f, 0x5d, 0x5b } \ ++ } ++ ++typedef struct grub_efi_dhcp4_protocol grub_efi_dhcp4_protocol_t; ++ ++enum grub_efi_dhcp4_state { ++ GRUB_EFI_DHCP4_STOPPED, ++ GRUB_EFI_DHCP4_INIT, ++ GRUB_EFI_DHCP4_SELECTING, ++ GRUB_EFI_DHCP4_REQUESTING, ++ GRUB_EFI_DHCP4_BOUND, ++ GRUB_EFI_DHCP4_RENEWING, ++ GRUB_EFI_DHCP4_REBINDING, ++ GRUB_EFI_DHCP4_INIT_REBOOT, ++ GRUB_EFI_DHCP4_REBOOTING ++}; ++ ++typedef enum grub_efi_dhcp4_state grub_efi_dhcp4_state_t; ++ ++struct grub_efi_dhcp4_header { ++ grub_efi_uint8_t op_code; ++ grub_efi_uint8_t hw_type; ++ grub_efi_uint8_t hw_addr_len; ++ grub_efi_uint8_t hops; ++ grub_efi_uint32_t xid; ++ grub_efi_uint16_t seconds; ++ grub_efi_uint16_t reserved; ++ grub_efi_ipv4_address_t client_addr; ++ grub_efi_ipv4_address_t your_addr; ++ grub_efi_ipv4_address_t server_addr; ++ grub_efi_ipv4_address_t gateway_addr; ++ grub_efi_uint8_t client_hw_addr[16]; ++ grub_efi_char8_t server_name[64]; ++ grub_efi_char8_t boot_file_name[128]; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp4_header grub_efi_dhcp4_header_t; ++ ++struct grub_efi_dhcp4_packet { ++ grub_efi_uint32_t size; ++ grub_efi_uint32_t length; ++ struct { ++ grub_efi_dhcp4_header_t header; ++ grub_efi_uint32_t magik; ++ grub_efi_uint8_t option[1]; ++ } dhcp4; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp4_packet grub_efi_dhcp4_packet_t; ++ ++struct grub_efi_dhcp4_listen_point { ++ grub_efi_ipv4_address_t listen_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_uint16_t listen_port; ++}; ++ ++typedef struct grub_efi_dhcp4_listen_point grub_efi_dhcp4_listen_point_t; ++ ++struct grub_efi_dhcp4_transmit_receive_token { ++ grub_efi_status_t status; ++ grub_efi_event_t completion_event; ++ grub_efi_ipv4_address_t remote_address; ++ grub_efi_uint16_t remote_port; ++ grub_efi_ipv4_address_t gateway_address; ++ grub_efi_uint32_t listen_point_count; ++ grub_efi_dhcp4_listen_point_t *listen_points; ++ grub_efi_uint32_t timeout_value; ++ grub_efi_dhcp4_packet_t *packet; ++ grub_efi_uint32_t response_count; ++ grub_efi_dhcp4_packet_t *response_list; ++}; ++ ++typedef struct grub_efi_dhcp4_transmit_receive_token grub_efi_dhcp4_transmit_receive_token_t; ++ ++enum grub_efi_dhcp4_event { ++ GRUB_EFI_DHCP4_SEND_DISCOVER = 0X01, ++ GRUB_EFI_DHCP4_RCVD_OFFER, ++ GRUB_EFI_DHCP4_SELECT_OFFER, ++ GRUB_EFI_DHCP4_SEND_REQUEST, ++ GRUB_EFI_DHCP4_RCVD_ACK, ++ GRUB_EFI_DHCP4_RCVD_NAK, ++ GRUB_EFI_DHCP4_SEND_DECLINE, ++ GRUB_EFI_DHCP4_BOUND_COMPLETED, ++ GRUB_EFI_DHCP4_ENTER_RENEWING, ++ GRUB_EFI_DHCP4_ENTER_REBINDING, ++ GRUB_EFI_DHCP4_ADDRESS_LOST, ++ GRUB_EFI_DHCP4_FAIL ++}; ++ ++typedef enum grub_efi_dhcp4_event grub_efi_dhcp4_event_t; ++ ++struct grub_efi_dhcp4_packet_option { ++ grub_efi_uint8_t op_code; ++ grub_efi_uint8_t length; ++ grub_efi_uint8_t data[1]; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp4_packet_option grub_efi_dhcp4_packet_option_t; ++ ++struct grub_efi_dhcp4_config_data { ++ grub_efi_uint32_t discover_try_count; ++ grub_efi_uint32_t *discover_timeout; ++ grub_efi_uint32_t request_try_count; ++ grub_efi_uint32_t *request_timeout; ++ grub_efi_ipv4_address_t client_address; ++ grub_efi_status_t (__grub_efi_api *dhcp4_callback) ( ++ grub_efi_dhcp4_protocol_t *this, ++ void *context, ++ grub_efi_dhcp4_state_t current_state, ++ grub_efi_dhcp4_event_t dhcp4_event, ++ grub_efi_dhcp4_packet_t *packet, ++ grub_efi_dhcp4_packet_t **new_packet ++ ); ++ void *callback_context; ++ grub_efi_uint32_t option_count; ++ grub_efi_dhcp4_packet_option_t **option_list; ++}; ++ ++typedef struct grub_efi_dhcp4_config_data grub_efi_dhcp4_config_data_t; ++ ++struct grub_efi_dhcp4_mode_data { ++ grub_efi_dhcp4_state_t state; ++ grub_efi_dhcp4_config_data_t config_data; ++ grub_efi_ipv4_address_t client_address; ++ grub_efi_mac_address_t client_mac_address; ++ grub_efi_ipv4_address_t server_address; ++ grub_efi_ipv4_address_t router_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_uint32_t lease_time; ++ grub_efi_dhcp4_packet_t *reply_packet; ++}; ++ ++typedef struct grub_efi_dhcp4_mode_data grub_efi_dhcp4_mode_data_t; ++ ++struct grub_efi_dhcp4_protocol { ++ grub_efi_status_t (__grub_efi_api *get_mode_data) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_mode_data_t *dhcp4_mode_data); ++ grub_efi_status_t (__grub_efi_api *configure) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_config_data_t *dhcp4_cfg_data); ++ grub_efi_status_t (__grub_efi_api *start) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_event_t completion_event); ++ grub_efi_status_t (__grub_efi_api *renew_rebind) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_boolean_t rebind_request, ++ grub_efi_event_t completion_event); ++ grub_efi_status_t (__grub_efi_api *release) (grub_efi_dhcp4_protocol_t *this); ++ grub_efi_status_t (__grub_efi_api *stop) (grub_efi_dhcp4_protocol_t *this); ++ grub_efi_status_t (__grub_efi_api *build) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_packet_t *seed_packet, ++ grub_efi_uint32_t delete_count, ++ grub_efi_uint8_t *delete_list, ++ grub_efi_uint32_t append_count, ++ grub_efi_dhcp4_packet_option_t *append_list[], ++ grub_efi_dhcp4_packet_t **new_packet); ++ grub_efi_status_t (__grub_efi_api *transmit_receive) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_transmit_receive_token_t *token); ++ grub_efi_status_t (__grub_efi_api *parse) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_packet_t *packet, ++ grub_efi_uint32_t *option_count, ++ grub_efi_dhcp4_packet_option_t *packet_option_list[]); ++}; ++ ++typedef struct grub_efi_dhcp6_protocol grub_efi_dhcp6_protocol_t; ++ ++struct grub_efi_dhcp6_retransmission { ++ grub_efi_uint32_t irt; ++ grub_efi_uint32_t mrc; ++ grub_efi_uint32_t mrt; ++ grub_efi_uint32_t mrd; ++}; ++ ++typedef struct grub_efi_dhcp6_retransmission grub_efi_dhcp6_retransmission_t; ++ ++enum grub_efi_dhcp6_event { ++ GRUB_EFI_DHCP6_SEND_SOLICIT, ++ GRUB_EFI_DHCP6_RCVD_ADVERTISE, ++ GRUB_EFI_DHCP6_SELECT_ADVERTISE, ++ GRUB_EFI_DHCP6_SEND_REQUEST, ++ GRUB_EFI_DHCP6_RCVD_REPLY, ++ GRUB_EFI_DHCP6_RCVD_RECONFIGURE, ++ GRUB_EFI_DHCP6_SEND_DECLINE, ++ GRUB_EFI_DHCP6_SEND_CONFIRM, ++ GRUB_EFI_DHCP6_SEND_RELEASE, ++ GRUB_EFI_DHCP6_SEND_RENEW, ++ GRUB_EFI_DHCP6_SEND_REBIND ++}; ++ ++typedef enum grub_efi_dhcp6_event grub_efi_dhcp6_event_t; ++ ++struct grub_efi_dhcp6_packet_option { ++ grub_efi_uint16_t op_code; ++ grub_efi_uint16_t op_len; ++ grub_efi_uint8_t data[1]; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp6_packet_option grub_efi_dhcp6_packet_option_t; ++ ++struct grub_efi_dhcp6_header { ++ grub_efi_uint32_t transaction_id:24; ++ grub_efi_uint32_t message_type:8; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp6_header grub_efi_dhcp6_header_t; ++ ++struct grub_efi_dhcp6_packet { ++ grub_efi_uint32_t size; ++ grub_efi_uint32_t length; ++ struct { ++ grub_efi_dhcp6_header_t header; ++ grub_efi_uint8_t option[1]; ++ } dhcp6; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp6_packet grub_efi_dhcp6_packet_t; ++ ++struct grub_efi_dhcp6_ia_address { ++ grub_efi_ipv6_address_t ip_address; ++ grub_efi_uint32_t preferred_lifetime; ++ grub_efi_uint32_t valid_lifetime; ++}; ++ ++typedef struct grub_efi_dhcp6_ia_address grub_efi_dhcp6_ia_address_t; ++ ++enum grub_efi_dhcp6_state { ++ GRUB_EFI_DHCP6_INIT, ++ GRUB_EFI_DHCP6_SELECTING, ++ GRUB_EFI_DHCP6_REQUESTING, ++ GRUB_EFI_DHCP6_DECLINING, ++ GRUB_EFI_DHCP6_CONFIRMING, ++ GRUB_EFI_DHCP6_RELEASING, ++ GRUB_EFI_DHCP6_BOUND, ++ GRUB_EFI_DHCP6_RENEWING, ++ GRUB_EFI_DHCP6_REBINDING ++}; ++ ++typedef enum grub_efi_dhcp6_state grub_efi_dhcp6_state_t; ++ ++#define GRUB_EFI_DHCP6_IA_TYPE_NA 3 ++#define GRUB_EFI_DHCP6_IA_TYPE_TA 4 ++ ++struct grub_efi_dhcp6_ia_descriptor { ++ grub_efi_uint16_t type; ++ grub_efi_uint32_t ia_id; ++}; ++ ++typedef struct grub_efi_dhcp6_ia_descriptor grub_efi_dhcp6_ia_descriptor_t; ++ ++struct grub_efi_dhcp6_ia { ++ grub_efi_dhcp6_ia_descriptor_t descriptor; ++ grub_efi_dhcp6_state_t state; ++ grub_efi_dhcp6_packet_t *reply_packet; ++ grub_efi_uint32_t ia_address_count; ++ grub_efi_dhcp6_ia_address_t ia_address[1]; ++}; ++ ++typedef struct grub_efi_dhcp6_ia grub_efi_dhcp6_ia_t; ++ ++struct grub_efi_dhcp6_duid { ++ grub_efi_uint16_t length; ++ grub_efi_uint8_t duid[1]; ++}; ++ ++typedef struct grub_efi_dhcp6_duid grub_efi_dhcp6_duid_t; ++ ++struct grub_efi_dhcp6_mode_data { ++ grub_efi_dhcp6_duid_t *client_id; ++ grub_efi_dhcp6_ia_t *ia; ++}; ++ ++typedef struct grub_efi_dhcp6_mode_data grub_efi_dhcp6_mode_data_t; ++ ++struct grub_efi_dhcp6_config_data { ++ grub_efi_status_t (__grub_efi_api *dhcp6_callback) (grub_efi_dhcp6_protocol_t this, ++ void *context, ++ grub_efi_dhcp6_state_t current_state, ++ grub_efi_dhcp6_event_t dhcp6_event, ++ grub_efi_dhcp6_packet_t *packet, ++ grub_efi_dhcp6_packet_t **new_packet); ++ void *callback_context; ++ grub_efi_uint32_t option_count; ++ grub_efi_dhcp6_packet_option_t **option_list; ++ grub_efi_dhcp6_ia_descriptor_t ia_descriptor; ++ grub_efi_event_t ia_info_event; ++ grub_efi_boolean_t reconfigure_accept; ++ grub_efi_boolean_t rapid_commit; ++ grub_efi_dhcp6_retransmission_t *solicit_retransmission; ++}; ++ ++typedef struct grub_efi_dhcp6_config_data grub_efi_dhcp6_config_data_t; ++ ++struct grub_efi_dhcp6_protocol { ++ grub_efi_status_t (__grub_efi_api *get_mode_data) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_dhcp6_mode_data_t *dhcp6_mode_data, ++ grub_efi_dhcp6_config_data_t *dhcp6_config_data); ++ grub_efi_status_t (__grub_efi_api *configure) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_dhcp6_config_data_t *dhcp6_cfg_data); ++ grub_efi_status_t (__grub_efi_api *start) (grub_efi_dhcp6_protocol_t *this); ++ grub_efi_status_t (__grub_efi_api *info_request) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_boolean_t send_client_id, ++ grub_efi_dhcp6_packet_option_t *option_request, ++ grub_efi_uint32_t option_count, ++ grub_efi_dhcp6_packet_option_t *option_list[], ++ grub_efi_dhcp6_retransmission_t *retransmission, ++ grub_efi_event_t timeout_event, ++ grub_efi_status_t (__grub_efi_api *reply_callback) (grub_efi_dhcp6_protocol_t *this, ++ void *context, ++ grub_efi_dhcp6_packet_t *packet), ++ void *callback_context); ++ grub_efi_status_t (__grub_efi_api *renew_rebind) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_boolean_t rebind_request); ++ grub_efi_status_t (__grub_efi_api *decline) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_uint32_t address_count, ++ grub_efi_ipv6_address_t *addresses); ++ grub_efi_status_t (__grub_efi_api *release) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_uint32_t address_count, ++ grub_efi_ipv6_address_t *addresses); ++ grub_efi_status_t (__grub_efi_api *stop) (grub_efi_dhcp6_protocol_t *this); ++ grub_efi_status_t (__grub_efi_api *parse) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_dhcp6_packet_t *packet, ++ grub_efi_uint32_t *option_count, ++ grub_efi_dhcp6_packet_option_t *packet_option_list[]); ++}; ++ ++#endif /* ! GRUB_EFI_DHCP_HEADER */ +diff --git a/include/grub/efi/disk.h b/include/grub/efi/disk.h +index 254475c84..6845c2f1f 100644 +--- a/include/grub/efi/disk.h ++++ b/include/grub/efi/disk.h +@@ -27,6 +27,8 @@ grub_efi_handle_t + EXPORT_FUNC(grub_efidisk_get_device_handle) (grub_disk_t disk); + char *EXPORT_FUNC(grub_efidisk_get_device_name) (grub_efi_handle_t *handle); + ++void EXPORT_FUNC(grub_efidisk_reenumerate_disks) (void); ++ + void grub_efidisk_init (void); + void grub_efidisk_fini (void); + +diff --git a/include/grub/efi/edid.h b/include/grub/efi/edid.h +index 43c0c4372..ac1b8e2fd 100644 +--- a/include/grub/efi/edid.h ++++ b/include/grub/efi/edid.h +@@ -33,7 +33,7 @@ + struct grub_efi_edid_override; + + typedef grub_efi_status_t +-(*grub_efi_edid_override_get_edid) (struct grub_efi_edid_override *this, ++(__grub_efi_api *grub_efi_edid_override_get_edid) (struct grub_efi_edid_override *this, + grub_efi_handle_t *childhandle, + grub_efi_uint32_t *attributes, + grub_efi_uintn_t *edidsize, +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index a5cd99e5a..7eed1bd79 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -36,6 +36,39 @@ struct linux_arch_kernel_header { + struct grub_pe_image_header pe_image_header; + }; + ++struct grub_arm_linux_pe_header ++{ ++ grub_uint32_t magic; ++ struct grub_pe32_coff_header coff; ++ struct grub_pe32_optional_header opt; ++}; ++ ++struct grub_arm64_linux_pe_header ++{ ++ grub_uint32_t magic; ++ struct grub_pe32_coff_header coff; ++ struct grub_pe64_optional_header opt; ++}; ++ ++#if defined(__arm__) ++# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE32_MAGIC ++# define grub_armxx_linux_pe_header grub_arm_linux_pe_header ++#endif ++ ++#if defined(__aarch64__) ++# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE64_MAGIC ++# define grub_armxx_linux_pe_header grub_arm64_linux_pe_header ++#endif ++ ++#define GRUB_EFI_GRUB_VARIABLE_GUID \ ++ { 0x91376aff, 0xcba6, 0x42be, \ ++ { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \ ++ } ++ ++/* Variables. */ ++extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table); ++extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle); ++ + /* Functions. */ + void *EXPORT_FUNC(grub_efi_locate_protocol) (grub_guid_t *protocol, + void *registration); +@@ -44,6 +77,11 @@ EXPORT_FUNC(grub_efi_locate_handle) (grub_efi_locate_search_type_t search_type, + grub_guid_t *protocol, + void *search_key, + grub_efi_uintn_t *num_handles); ++grub_efi_status_t ++EXPORT_FUNC(grub_efi_connect_controller) (grub_efi_handle_t controller_handle, ++ grub_efi_handle_t *driver_image_handle, ++ grub_efi_device_path_protocol_t *remaining_device_path, ++ grub_efi_boolean_t recursive); + void *EXPORT_FUNC(grub_efi_open_protocol) (grub_efi_handle_t handle, + grub_guid_t *protocol, + grub_efi_uint32_t attributes); +@@ -61,6 +99,9 @@ EXPORT_FUNC(grub_efi_allocate_fixed) (grub_efi_physical_address_t address, + grub_efi_uintn_t pages); + void * + EXPORT_FUNC(grub_efi_allocate_any_pages) (grub_efi_uintn_t pages); ++void * ++EXPORT_FUNC(grub_efi_allocate_pages_max) (grub_efi_physical_address_t max, ++ grub_efi_uintn_t pages); + void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address, + grub_efi_uintn_t pages); + grub_efi_uintn_t EXPORT_FUNC(grub_efi_find_mmap_size) (void); +@@ -71,6 +112,33 @@ EXPORT_FUNC(grub_efi_get_memory_map) (grub_efi_uintn_t *memory_map_size, + grub_efi_uintn_t *descriptor_size, + grub_efi_uint32_t *descriptor_version); + void grub_efi_memory_fini (void); ++ ++static inline grub_efi_status_t ++__attribute__((__unused__)) ++grub_efi_allocate_pool (grub_efi_memory_type_t pool_type, ++ grub_efi_uintn_t buffer_size, ++ void **buffer) ++{ ++ grub_efi_boot_services_t *b; ++ grub_efi_status_t status; ++ ++ b = grub_efi_system_table->boot_services; ++ status = b->allocate_pool(pool_type, buffer_size, buffer); ++ return status; ++} ++ ++static inline grub_efi_status_t ++__attribute__((__unused__)) ++grub_efi_free_pool (void *buffer) ++{ ++ grub_efi_boot_services_t *b; ++ grub_efi_status_t status; ++ ++ b = grub_efi_system_table->boot_services; ++ status = b->free_pool(buffer); ++ return status; ++} ++ + grub_efi_loaded_image_t *EXPORT_FUNC(grub_efi_get_loaded_image) (grub_efi_handle_t image_handle); + void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp); + char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp); +@@ -122,6 +190,9 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd, + void * + EXPORT_FUNC (grub_efi_find_configuration_table) (const grub_guid_t *target_guid); + ++extern grub_addr_t EXPORT_VAR(grub_stack_addr); ++extern grub_size_t EXPORT_VAR(grub_stack_size); ++ + #if defined(__arm__) || defined(__aarch64__) || defined(__riscv) || defined(__loongarch__) + void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void); + grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *); +@@ -130,7 +201,44 @@ grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *); + grub_err_t grub_arch_efi_linux_load_image_header(grub_file_t file, + struct linux_arch_kernel_header *lh); + grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, grub_size_t size, +- char *args); ++ char *args, int nx_enabled); ++grub_efi_status_t ++EXPORT_FUNC (grub_efi_load_image) (grub_efi_boolean_t boot_policy, ++ grub_efi_handle_t parent_image_handle, ++ grub_efi_device_path_t *file_path, ++ void *source_buffer, grub_efi_uintn_t source_size, ++ grub_efi_handle_t *image_handle); ++ ++grub_efi_status_t ++EXPORT_FUNC (grub_efi_start_image) (grub_efi_handle_t image_handle, ++ grub_efi_uintn_t *exit_data_size, ++ grub_efi_char16_t **exit_data); ++ ++grub_efi_status_t ++EXPORT_FUNC (grub_efi_unload_image) (grub_efi_handle_t image_handle); ++ ++typedef struct grub_efi_loader ++{ ++ grub_efi_status_t (__grub_efi_api *load_image) (grub_efi_boolean_t boot_policy, ++ grub_efi_handle_t parent_image_handle, ++ grub_efi_device_path_t *file_path, ++ void *source_buffer, ++ grub_efi_uintn_t source_size, ++ grub_efi_handle_t *image_handle); ++ ++ grub_efi_status_t (__grub_efi_api *start_image) (grub_efi_handle_t image_handle, ++ grub_efi_uintn_t *exit_data_size, ++ grub_efi_char16_t **exit_data); ++ ++ grub_efi_status_t (__grub_efi_api *unload_image) (grub_efi_handle_t image_handle); ++} grub_efi_loader_t; ++ ++grub_err_t ++EXPORT_FUNC (grub_efi_register_loader) (const grub_efi_loader_t *loader); ++ ++grub_err_t ++EXPORT_FUNC (grub_efi_unregister_loader) (const grub_efi_loader_t *loader); ++ + + grub_addr_t grub_efi_section_addr (const char *section); + +@@ -140,10 +248,7 @@ void grub_efi_init (void); + void grub_efi_fini (void); + void grub_efi_set_prefix (void); + +-/* Variables. */ +-extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table); +-extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle); +- ++/* More variables. */ + extern int EXPORT_VAR(grub_efi_is_finished); + + struct grub_net_card; +@@ -151,4 +256,6 @@ struct grub_net_card; + grub_efi_handle_t + grub_efinet_get_device_handle (struct grub_net_card *card); + ++grub_err_t EXPORT_FUNC(grub_efi_status_to_err) (grub_efi_status_t status); ++ + #endif /* ! GRUB_EFI_EFI_HEADER */ +diff --git a/include/grub/efi/http.h b/include/grub/efi/http.h +new file mode 100644 +index 000000000..242d001b6 +--- /dev/null ++++ b/include/grub/efi/http.h +@@ -0,0 +1,215 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_EFI_HTTP_HEADER ++#define GRUB_EFI_HTTP_HEADER 1 ++ ++#include ++#include ++#include ++ ++#define GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \ ++ { 0xbdc8e6af, 0xd9bc, 0x4379, \ ++ { 0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c } \ ++ } ++ ++#define GRUB_EFI_HTTP_PROTOCOL_GUID \ ++ { 0x7A59B29B, 0x910B, 0x4171, \ ++ { 0x82, 0x42, 0xA8, 0x5A, 0x0D, 0xF2, 0x5B, 0x5B } \ ++ } ++ ++#define EFIHTTP_WAIT_TIME 10000 // 10000ms = 10s ++#define EFIHTTP_RX_BUF_LEN 10240 ++ ++//****************************************** ++// Protocol Interface Structure ++//****************************************** ++struct grub_efi_http; ++ ++//****************************************** ++// EFI_HTTP_VERSION ++//****************************************** ++typedef enum { ++ GRUB_EFI_HTTPVERSION10, ++ GRUB_EFI_HTTPVERSION11, ++ GRUB_EFI_HTTPVERSIONUNSUPPORTED ++} grub_efi_http_version_t; ++ ++//****************************************** ++// EFI_HTTPv4_ACCESS_POINT ++//****************************************** ++typedef struct { ++ grub_efi_boolean_t use_default_address; ++ grub_efi_ipv4_address_t local_address; ++ grub_efi_ipv4_address_t local_subnet; ++ grub_efi_uint16_t local_port; ++} grub_efi_httpv4_access_point_t; ++ ++//****************************************** ++// EFI_HTTPv6_ACCESS_POINT ++//****************************************** ++typedef struct { ++ grub_efi_ipv6_address_t local_address; ++ grub_efi_uint16_t local_port; ++} grub_efi_httpv6_access_point_t; ++ ++//****************************************** ++// EFI_HTTP_CONFIG_DATA ++//****************************************** ++typedef struct { ++ grub_efi_http_version_t http_version; ++ grub_efi_uint32_t timeout_millisec; ++ grub_efi_boolean_t local_address_is_ipv6; ++ union { ++ grub_efi_httpv4_access_point_t *ipv4_node; ++ grub_efi_httpv6_access_point_t *ipv6_node; ++ } access_point; ++} grub_efi_http_config_data_t; ++ ++//****************************************** ++// EFI_HTTP_METHOD ++//****************************************** ++typedef enum { ++ GRUB_EFI_HTTPMETHODGET, ++ GRUB_EFI_HTTPMETHODPOST, ++ GRUB_EFI_HTTPMETHODPATCH, ++ GRUB_EFI_HTTPMETHODOPTIONS, ++ GRUB_EFI_HTTPMETHODCONNECT, ++ GRUB_EFI_HTTPMETHODHEAD, ++ GRUB_EFI_HTTPMETHODPUT, ++ GRUB_EFI_HTTPMETHODDELETE, ++ GRUB_EFI_HTTPMETHODTRACE, ++} grub_efi_http_method_t; ++ ++//****************************************** ++// EFI_HTTP_REQUEST_DATA ++//****************************************** ++typedef struct { ++ grub_efi_http_method_t method; ++ grub_efi_char16_t *url; ++} grub_efi_http_request_data_t; ++ ++typedef enum { ++ GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS = 0, ++ GRUB_EFI_HTTP_STATUS_100_CONTINUE, ++ GRUB_EFI_HTTP_STATUS_101_SWITCHING_PROTOCOLS, ++ GRUB_EFI_HTTP_STATUS_200_OK, ++ GRUB_EFI_HTTP_STATUS_201_CREATED, ++ GRUB_EFI_HTTP_STATUS_202_ACCEPTED, ++ GRUB_EFI_HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION, ++ GRUB_EFI_HTTP_STATUS_204_NO_CONTENT, ++ GRUB_EFI_HTTP_STATUS_205_RESET_CONTENT, ++ GRUB_EFI_HTTP_STATUS_206_PARTIAL_CONTENT, ++ GRUB_EFI_HTTP_STATUS_300_MULTIPLE_CHIOCES, ++ GRUB_EFI_HTTP_STATUS_301_MOVED_PERMANENTLY, ++ GRUB_EFI_HTTP_STATUS_302_FOUND, ++ GRUB_EFI_HTTP_STATUS_303_SEE_OTHER, ++ GRUB_EFI_HTTP_STATUS_304_NOT_MODIFIED, ++ GRUB_EFI_HTTP_STATUS_305_USE_PROXY, ++ GRUB_EFI_HTTP_STATUS_307_TEMPORARY_REDIRECT, ++ GRUB_EFI_HTTP_STATUS_400_BAD_REQUEST, ++ GRUB_EFI_HTTP_STATUS_401_UNAUTHORIZED, ++ GRUB_EFI_HTTP_STATUS_402_PAYMENT_REQUIRED, ++ GRUB_EFI_HTTP_STATUS_403_FORBIDDEN, ++ GRUB_EFI_HTTP_STATUS_404_NOT_FOUND, ++ GRUB_EFI_HTTP_STATUS_405_METHOD_NOT_ALLOWED, ++ GRUB_EFI_HTTP_STATUS_406_NOT_ACCEPTABLE, ++ GRUB_EFI_HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED, ++ GRUB_EFI_HTTP_STATUS_408_REQUEST_TIME_OUT, ++ GRUB_EFI_HTTP_STATUS_409_CONFLICT, ++ GRUB_EFI_HTTP_STATUS_410_GONE, ++ GRUB_EFI_HTTP_STATUS_411_LENGTH_REQUIRED, ++ GRUB_EFI_HTTP_STATUS_412_PRECONDITION_FAILED, ++ GRUB_EFI_HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE, ++ GRUB_EFI_HTTP_STATUS_414_REQUEST_URI_TOO_LARGE, ++ GRUB_EFI_HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE, ++ GRUB_EFI_HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED, ++ GRUB_EFI_HTTP_STATUS_417_EXPECTATION_FAILED, ++ GRUB_EFI_HTTP_STATUS_500_INTERNAL_SERVER_ERROR, ++ GRUB_EFI_HTTP_STATUS_501_NOT_IMPLEMENTED, ++ GRUB_EFI_HTTP_STATUS_502_BAD_GATEWAY, ++ GRUB_EFI_HTTP_STATUS_503_SERVICE_UNAVAILABLE, ++ GRUB_EFI_HTTP_STATUS_504_GATEWAY_TIME_OUT, ++ GRUB_EFI_HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED ++} grub_efi_http_status_code_t; ++ ++//****************************************** ++// EFI_HTTP_RESPONSE_DATA ++//****************************************** ++typedef struct { ++ grub_efi_http_status_code_t status_code; ++} grub_efi_http_response_data_t; ++ ++//****************************************** ++// EFI_HTTP_HEADER ++//****************************************** ++typedef struct { ++ grub_efi_char8_t *field_name; ++ grub_efi_char8_t *field_value; ++} grub_efi_http_header_t; ++ ++//****************************************** ++// EFI_HTTP_MESSAGE ++//****************************************** ++typedef struct { ++ union { ++ grub_efi_http_request_data_t *request; ++ grub_efi_http_response_data_t *response; ++ } data; ++ grub_efi_uintn_t header_count; ++ grub_efi_http_header_t *headers; ++ grub_efi_uintn_t body_length; ++ void *body; ++} grub_efi_http_message_t; ++ ++//****************************************** ++// EFI_HTTP_TOKEN ++//****************************************** ++typedef struct { ++ grub_efi_event_t event; ++ grub_efi_status_t status; ++ grub_efi_http_message_t *message; ++} grub_efi_http_token_t; ++ ++struct grub_efi_http { ++ grub_efi_status_t ++ (__grub_efi_api *get_mode_data) (struct grub_efi_http *this, ++ grub_efi_http_config_data_t *http_config_data); ++ ++ grub_efi_status_t ++ (__grub_efi_api *configure) (struct grub_efi_http *this, ++ grub_efi_http_config_data_t *http_config_data); ++ ++ grub_efi_status_t ++ (__grub_efi_api *request) (struct grub_efi_http *this, ++ grub_efi_http_token_t *token); ++ ++ grub_efi_status_t ++ (__grub_efi_api *cancel) (struct grub_efi_http *this, ++ grub_efi_http_token_t *token); ++ ++ grub_efi_status_t ++ (__grub_efi_api *response) (struct grub_efi_http *this, ++ grub_efi_http_token_t *token); ++ ++ grub_efi_status_t ++ (__grub_efi_api *poll) (struct grub_efi_http *this); ++}; ++typedef struct grub_efi_http grub_efi_http_t; ++ ++#endif /* !GRUB_EFI_HTTP_HEADER */ +diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h +new file mode 100644 +index 000000000..5b4e626c3 +--- /dev/null ++++ b/include/grub/efi/linux.h +@@ -0,0 +1,41 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2014 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++#ifndef GRUB_EFI_LINUX_HEADER ++#define GRUB_EFI_LINUX_HEADER 1 ++ ++#include ++#include ++#include ++ ++#define GRUB_MOK_POLICY_NX_REQUIRED 0x1 ++ ++grub_err_t ++EXPORT_FUNC(grub_efi_linux_boot) (grub_addr_t kernel_address, ++ grub_size_t kernel_size, ++ grub_off_t handover_offset, ++ void *kernel_param, int nx_enabled); ++ ++grub_err_t ++EXPORT_FUNC(grub_efi_check_nx_image_support) (grub_addr_t kernel_addr, ++ grub_size_t kernel_size, ++ int *nx_supported); ++ ++grub_err_t ++EXPORT_FUNC(grub_efi_check_nx_required) (int *nx_required); ++ ++#endif /* ! GRUB_EFI_LINUX_HEADER */ +diff --git a/include/grub/efi/pci.h b/include/grub/efi/pci.h +index b17245549..a90f61042 100644 +--- a/include/grub/efi/pci.h ++++ b/include/grub/efi/pci.h +@@ -48,7 +48,7 @@ typedef enum + struct grub_efi_pci_io; + + typedef grub_efi_status_t +-(*grub_efi_pci_io_mem_t) (struct grub_efi_pci_io *this, ++(__grub_efi_api *grub_efi_pci_io_mem_t) (struct grub_efi_pci_io *this, + grub_efi_pci_io_width_t width, + grub_efi_uint8_t bar_index, + grub_efi_uint64_t offset, +@@ -56,7 +56,7 @@ typedef grub_efi_status_t + void *buffer); + + typedef grub_efi_status_t +-(*grub_efi_pci_io_config_t) (struct grub_efi_pci_io *this, ++(__grub_efi_api *grub_efi_pci_io_config_t) (struct grub_efi_pci_io *this, + grub_efi_pci_io_width_t width, + grub_efi_uint32_t offset, + grub_efi_uintn_t count, +@@ -113,7 +113,7 @@ typedef enum + grub_efi_pci_io_attribute_operation_t; + + typedef grub_efi_status_t +-(*grub_efi_pci_io_poll_io_mem_t) (struct grub_efi_pci_io *this, ++(__grub_efi_api *grub_efi_pci_io_poll_io_mem_t) (struct grub_efi_pci_io *this, + grub_efi_pci_io_width_t width, + grub_efi_uint8_t bar_ndex, + grub_efi_uint64_t offset, +@@ -123,7 +123,7 @@ typedef grub_efi_status_t + grub_efi_uint64_t *result); + + typedef grub_efi_status_t +-(*grub_efi_pci_io_copy_mem_t) (struct grub_efi_pci_io *this, ++(__grub_efi_api *grub_efi_pci_io_copy_mem_t) (struct grub_efi_pci_io *this, + grub_efi_pci_io_width_t width, + grub_efi_uint8_t dest_bar_index, + grub_efi_uint64_t dest_offset, +@@ -132,7 +132,7 @@ typedef grub_efi_status_t + grub_efi_uintn_t count); + + typedef grub_efi_status_t +-(*grub_efi_pci_io_map_t) (struct grub_efi_pci_io *this, ++(__grub_efi_api *grub_efi_pci_io_map_t) (struct grub_efi_pci_io *this, + grub_efi_pci_io_operation_t operation, + void *host_address, + grub_efi_uintn_t *number_of_bytes, +@@ -140,11 +140,11 @@ typedef grub_efi_status_t + void **mapping); + + typedef grub_efi_status_t +-(*grub_efi_pci_io_unmap_t) (struct grub_efi_pci_io *this, ++(__grub_efi_api *grub_efi_pci_io_unmap_t) (struct grub_efi_pci_io *this, + void *mapping); + + typedef grub_efi_status_t +-(*grub_efi_pci_io_allocate_buffer_t) (struct grub_efi_pci_io *this, ++(__grub_efi_api *grub_efi_pci_io_allocate_buffer_t) (struct grub_efi_pci_io *this, + grub_efi_allocate_type_t type, + grub_efi_memory_type_t memory_type, + grub_efi_uintn_t pages, +@@ -152,7 +152,7 @@ typedef grub_efi_status_t + grub_efi_uint64_t attributes); + + typedef grub_efi_status_t +-(*grub_efi_pci_io_free_buffer_t) (struct grub_efi_pci_io *this, ++(__grub_efi_api *grub_efi_pci_io_free_buffer_t) (struct grub_efi_pci_io *this, + grub_efi_allocate_type_t type, + grub_efi_memory_type_t memory_type, + grub_efi_uintn_t pages, +@@ -160,29 +160,29 @@ typedef grub_efi_status_t + grub_efi_uint64_t attributes); + + typedef grub_efi_status_t +-(*grub_efi_pci_io_flush_t) (struct grub_efi_pci_io *this); ++(__grub_efi_api *grub_efi_pci_io_flush_t) (struct grub_efi_pci_io *this); + + typedef grub_efi_status_t +-(*grub_efi_pci_io_get_location_t) (struct grub_efi_pci_io *this, ++(__grub_efi_api *grub_efi_pci_io_get_location_t) (struct grub_efi_pci_io *this, + grub_efi_uintn_t *segment_number, + grub_efi_uintn_t *bus_number, + grub_efi_uintn_t *device_number, + grub_efi_uintn_t *function_number); + + typedef grub_efi_status_t +-(*grub_efi_pci_io_attributes_t) (struct grub_efi_pci_io *this, ++(__grub_efi_api *grub_efi_pci_io_attributes_t) (struct grub_efi_pci_io *this, + grub_efi_pci_io_attribute_operation_t operation, + grub_efi_uint64_t attributes, + grub_efi_uint64_t *result); + + typedef grub_efi_status_t +-(*grub_efi_pci_io_get_bar_attributes_t) (struct grub_efi_pci_io *this, ++(__grub_efi_api *grub_efi_pci_io_get_bar_attributes_t) (struct grub_efi_pci_io *this, + grub_efi_uint8_t bar_index, + grub_efi_uint64_t *supports, + void **resources); + + typedef grub_efi_status_t +-(*grub_efi_pci_io_set_bar_attributes_t) (struct grub_efi_pci_io *this, ++(__grub_efi_api *grub_efi_pci_io_set_bar_attributes_t) (struct grub_efi_pci_io *this, + grub_efi_uint64_t attributes, + grub_efi_uint8_t bar_index, + grub_efi_uint64_t *offset, +@@ -212,12 +212,12 @@ struct grub_efi_pci_root_io; + + typedef struct + { +- grub_efi_status_t(*read) (struct grub_efi_pci_root_io *this, ++ grub_efi_status_t(__grub_efi_api *read) (struct grub_efi_pci_root_io *this, + grub_efi_pci_io_width_t width, + grub_efi_uint64_t address, + grub_efi_uintn_t count, + void *buffer); +- grub_efi_status_t(*write) (struct grub_efi_pci_root_io *this, ++ grub_efi_status_t(__grub_efi_api *write) (struct grub_efi_pci_root_io *this, + grub_efi_pci_io_width_t width, + grub_efi_uint64_t address, + grub_efi_uintn_t count, +@@ -237,7 +237,7 @@ typedef enum + grub_efi_pci_root_io_operation_t; + + typedef grub_efi_status_t +-(*grub_efi_pci_root_io_poll_io_mem_t) (struct grub_efi_pci_root_io *this, ++(__grub_efi_api *grub_efi_pci_root_io_poll_io_mem_t) (struct grub_efi_pci_root_io *this, + grub_efi_pci_io_width_t width, + grub_efi_uint64_t address, + grub_efi_uint64_t mask, +@@ -246,7 +246,7 @@ typedef grub_efi_status_t + grub_efi_uint64_t *result); + + typedef grub_efi_status_t +-(*grub_efi_pci_root_io_copy_mem_t) (struct grub_efi_pci_root_io *this, ++(__grub_efi_api *grub_efi_pci_root_io_copy_mem_t) (struct grub_efi_pci_root_io *this, + grub_efi_pci_io_width_t width, + grub_efi_uint64_t dest_offset, + grub_efi_uint64_t src_offset, +@@ -254,7 +254,7 @@ typedef grub_efi_status_t + + + typedef grub_efi_status_t +-(*grub_efi_pci_root_io_map_t) (struct grub_efi_pci_root_io *this, ++(__grub_efi_api *grub_efi_pci_root_io_map_t) (struct grub_efi_pci_root_io *this, + grub_efi_pci_root_io_operation_t operation, + void *host_address, + grub_efi_uintn_t *number_of_bytes, +@@ -262,11 +262,11 @@ typedef grub_efi_status_t + void **mapping); + + typedef grub_efi_status_t +-(*grub_efi_pci_root_io_unmap_t) (struct grub_efi_pci_root_io *this, ++(__grub_efi_api *grub_efi_pci_root_io_unmap_t) (struct grub_efi_pci_root_io *this, + void *mapping); + + typedef grub_efi_status_t +-(*grub_efi_pci_root_io_allocate_buffer_t) (struct grub_efi_pci_root_io *this, ++(__grub_efi_api *grub_efi_pci_root_io_allocate_buffer_t) (struct grub_efi_pci_root_io *this, + grub_efi_allocate_type_t type, + grub_efi_memory_type_t memory_type, + grub_efi_uintn_t pages, +@@ -274,26 +274,26 @@ typedef grub_efi_status_t + grub_efi_uint64_t attributes); + + typedef grub_efi_status_t +-(*grub_efi_pci_root_io_free_buffer_t) (struct grub_efi_pci_root_io *this, ++(__grub_efi_api *grub_efi_pci_root_io_free_buffer_t) (struct grub_efi_pci_root_io *this, + grub_efi_uintn_t pages, + void **host_address); + + typedef grub_efi_status_t +-(*grub_efi_pci_root_io_flush_t) (struct grub_efi_pci_root_io *this); ++(__grub_efi_api *grub_efi_pci_root_io_flush_t) (struct grub_efi_pci_root_io *this); + + typedef grub_efi_status_t +-(*grub_efi_pci_root_io_get_attributes_t) (struct grub_efi_pci_root_io *this, ++(__grub_efi_api *grub_efi_pci_root_io_get_attributes_t) (struct grub_efi_pci_root_io *this, + grub_efi_uint64_t *supports, + void **resources); + + typedef grub_efi_status_t +-(*grub_efi_pci_root_io_set_attributes_t) (struct grub_efi_pci_root_io *this, ++(__grub_efi_api *grub_efi_pci_root_io_set_attributes_t) (struct grub_efi_pci_root_io *this, + grub_efi_uint64_t attributes, + grub_efi_uint64_t *offset, + grub_efi_uint64_t *length); + + typedef grub_efi_status_t +-(*grub_efi_pci_root_io_configuration_t) (struct grub_efi_pci_root_io *this, ++(__grub_efi_api *grub_efi_pci_root_io_configuration_t) (struct grub_efi_pci_root_io *this, + void **resources); + + struct grub_efi_pci_root_io { +diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h +index 4e6e9d254..a4d62373c 100644 +--- a/include/grub/efi/pe32.h ++++ b/include/grub/efi/pe32.h +@@ -46,7 +46,30 @@ + + #define GRUB_PE32_MSDOS_STUB_SIZE 0x80 + +-#define GRUB_PE32_MAGIC 0x5a4d ++#define GRUB_DOS_MAGIC 0x5a4d ++ ++struct grub_dos_header ++{ ++ grub_uint16_t magic; ++ grub_uint16_t cblp; ++ grub_uint16_t cp; ++ grub_uint16_t crlc; ++ grub_uint16_t cparhdr; ++ grub_uint16_t minalloc; ++ grub_uint16_t maxalloc; ++ grub_uint16_t ss; ++ grub_uint16_t sp; ++ grub_uint16_t csum; ++ grub_uint16_t ip; ++ grub_uint16_t cs; ++ grub_uint16_t lfarlc; ++ grub_uint16_t ovno; ++ grub_uint16_t res0[4]; ++ grub_uint16_t oemid; ++ grub_uint16_t oeminfo; ++ grub_uint16_t res1[10]; ++ grub_uint32_t lfanew; ++}; + + struct grub_msdos_image_header + { +@@ -171,6 +194,8 @@ struct grub_pe32_optional_header + struct grub_pe32_data_directory reserved_entry; + }; + ++#define GRUB_PE32_NX_COMPAT 0x0100 ++ + struct grub_pe64_optional_header + { + grub_uint16_t magic; +@@ -231,12 +256,18 @@ struct grub_pe64_optional_header + + #define GRUB_PE32_SUBSYSTEM_EFI_APPLICATION 10 + ++#define GRUB_PE32_NX_COMPAT 0x0100 ++ + #define GRUB_PE32_NUM_DATA_DIRECTORIES 16 + + struct grub_pe32_section_table + { + char name[8]; +- grub_uint32_t virtual_size; ++ union ++ { ++ grub_uint32_t physical_address; ++ grub_uint32_t virtual_size; ++ }; + grub_uint32_t virtual_address; + grub_uint32_t raw_data_size; + grub_uint32_t raw_data_offset; +@@ -247,12 +278,18 @@ struct grub_pe32_section_table + grub_uint32_t characteristics; + }; + ++#define GRUB_PE32_SCN_TYPE_NO_PAD 0x00000008 + #define GRUB_PE32_SCN_CNT_CODE 0x00000020 + #define GRUB_PE32_SCN_CNT_INITIALIZED_DATA 0x00000040 +-#define GRUB_PE32_SCN_MEM_DISCARDABLE 0x02000000 +-#define GRUB_PE32_SCN_MEM_EXECUTE 0x20000000 +-#define GRUB_PE32_SCN_MEM_READ 0x40000000 +-#define GRUB_PE32_SCN_MEM_WRITE 0x80000000 ++#define GRUB_PE32_SCN_CNT_UNINITIALIZED_DATA 0x00000080 ++#define GRUB_PE32_SCN_LNK_OTHER 0x00000100 ++#define GRUB_PE32_SCN_LNK_INFO 0x00000200 ++#define GRUB_PE32_SCN_LNK_REMOVE 0x00000800 ++#define GRUB_PE32_SCN_LNK_COMDAT 0x00001000 ++#define GRUB_PE32_SCN_GPREL 0x00008000 ++#define GRUB_PE32_SCN_MEM_16BIT 0x00020000 ++#define GRUB_PE32_SCN_MEM_LOCKED 0x00040000 ++#define GRUB_PE32_SCN_MEM_PRELOAD 0x00080000 + + #define GRUB_PE32_SCN_ALIGN_1BYTES 0x00100000 + #define GRUB_PE32_SCN_ALIGN_2BYTES 0x00200000 +@@ -261,11 +298,28 @@ struct grub_pe32_section_table + #define GRUB_PE32_SCN_ALIGN_16BYTES 0x00500000 + #define GRUB_PE32_SCN_ALIGN_32BYTES 0x00600000 + #define GRUB_PE32_SCN_ALIGN_64BYTES 0x00700000 ++#define GRUB_PE32_SCN_ALIGN_128BYTES 0x00800000 ++#define GRUB_PE32_SCN_ALIGN_256BYTES 0x00900000 ++#define GRUB_PE32_SCN_ALIGN_512BYTES 0x00A00000 ++#define GRUB_PE32_SCN_ALIGN_1024BYTES 0x00B00000 ++#define GRUB_PE32_SCN_ALIGN_2048BYTES 0x00C00000 ++#define GRUB_PE32_SCN_ALIGN_4096BYTES 0x00D00000 ++#define GRUB_PE32_SCN_ALIGN_8192BYTES 0x00E00000 + + #define GRUB_PE32_SCN_ALIGN_SHIFT 20 + #define GRUB_PE32_SCN_ALIGN_MASK 7 + +-#define GRUB_PE32_SIGNATURE_SIZE 4 ++#define GRUB_PE32_SCN_LNK_NRELOC_OVFL 0x01000000 ++#define GRUB_PE32_SCN_MEM_DISCARDABLE 0x02000000 ++#define GRUB_PE32_SCN_MEM_NOT_CACHED 0x04000000 ++#define GRUB_PE32_SCN_MEM_NOT_PAGED 0x08000000 ++#define GRUB_PE32_SCN_MEM_SHARED 0x10000000 ++#define GRUB_PE32_SCN_MEM_EXECUTE 0x20000000 ++#define GRUB_PE32_SCN_MEM_READ 0x40000000 ++#define GRUB_PE32_SCN_MEM_WRITE 0x80000000 ++ ++#define GRUB_PE32_SIGNATURE_SIZE 4 ++#define GRUB_PE32_SIGNATURE "PE\0\0" + + #if GRUB_TARGET_SIZEOF_VOID_P == 8 + #define GRUB_PE32_NATIVE_MAGIC GRUB_PE32_PE64_MAGIC +@@ -290,6 +344,21 @@ struct grub_pe_image_header + #endif + }; + ++struct grub_pe32_header_32 ++{ ++ char signature[GRUB_PE32_SIGNATURE_SIZE]; ++ struct grub_pe32_coff_header coff_header; ++ struct grub_pe32_optional_header optional_header; ++}; ++ ++struct grub_pe32_header_64 ++{ ++ char signature[GRUB_PE32_SIGNATURE_SIZE]; ++ struct grub_pe32_coff_header coff_header; ++ struct grub_pe64_optional_header optional_header; ++}; ++ ++ + struct grub_pe32_fixup_block + { + grub_uint32_t page_rva; +diff --git a/include/grub/efiemu/runtime.h b/include/grub/efiemu/runtime.h +index 2ff429845..6363fd522 100644 +--- a/include/grub/efiemu/runtime.h ++++ b/include/grub/efiemu/runtime.h +@@ -33,5 +33,5 @@ struct efi_variable + grub_uint32_t namelen; + grub_uint32_t size; + grub_efi_uint32_t attributes; +-} GRUB_PACKED; ++} GRUB_PACKED GRUB_ALIGNED(8); + #endif /* ! GRUB_EFI_EMU_RUNTIME_HEADER */ +diff --git a/include/grub/emu/config.h b/include/grub/emu/config.h +index 875d5896c..c9a7e5f4a 100644 +--- a/include/grub/emu/config.h ++++ b/include/grub/emu/config.h +@@ -37,6 +37,7 @@ struct grub_util_config + { + int is_cryptodisk_enabled; + char *grub_distributor; ++ int is_suse_btrfs_snapshot_enabled; + }; + + void +diff --git a/include/grub/emu/exec.h b/include/grub/emu/exec.h +index 1b61b4a2e..e82f13215 100644 +--- a/include/grub/emu/exec.h ++++ b/include/grub/emu/exec.h +@@ -36,7 +36,7 @@ grub_util_exec_redirect_all (const char *const *argv, const char *stdin_file, + int + EXPORT_FUNC(grub_util_exec) (const char *const *argv); + int +-grub_util_exec_redirect (const char *const *argv, const char *stdin_file, ++EXPORT_FUNC(grub_util_exec_redirect) (const char *const *argv, const char *stdin_file, + const char *stdout_file); + int + grub_util_exec_redirect_null (const char *const *argv); +diff --git a/include/grub/emu/getroot.h b/include/grub/emu/getroot.h +index 73fa2d34a..9c642ae3f 100644 +--- a/include/grub/emu/getroot.h ++++ b/include/grub/emu/getroot.h +@@ -53,6 +53,11 @@ char ** + grub_find_root_devices_from_mountinfo (const char *dir, char **relroot); + #endif + ++#ifdef __linux__ ++char * ++grub_util_get_btrfs_subvol (const char *path, char **mount_path); ++#endif ++ + /* Devmapper functions provided by getroot_devmapper.c. */ + void + grub_util_pull_devmapper (const char *os_dev); +diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h +index 01056954b..f3a712a8b 100644 +--- a/include/grub/emu/misc.h ++++ b/include/grub/emu/misc.h +@@ -59,6 +59,8 @@ void EXPORT_FUNC(grub_util_error) (const char *fmt, ...) __attribute__ ((format + + void EXPORT_FUNC(grub_util_set_kexecute) (void); + int EXPORT_FUNC(grub_util_get_kexecute) (void) WARN_UNUSED_RESULT; ++void EXPORT_FUNC(grub_util_set_switch_root) (void); ++int EXPORT_FUNC(grub_util_get_switch_root) (void); + + grub_uint64_t EXPORT_FUNC (grub_util_get_cpu_time_ms) (void); + +diff --git a/include/grub/err.h b/include/grub/err.h +index 1c07034cd..3c587b9b8 100644 +--- a/include/grub/err.h ++++ b/include/grub/err.h +@@ -86,8 +86,12 @@ struct grub_error_saved + extern grub_err_t EXPORT_VAR(grub_errno); + extern char EXPORT_VAR(grub_errmsg)[GRUB_MAX_ERRMSG]; + +-grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *fmt, ...) +- __attribute__ ((format (GNU_PRINTF, 2, 3))); ++grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *file, const int line, const char *fmt, ...) ++ __attribute__ ((format (GNU_PRINTF, 4, 5))); ++ ++#define grub_error(n, fmt, ...) grub_error (n, __FILE__, __LINE__, fmt, ##__VA_ARGS__) ++ ++ + void EXPORT_FUNC(grub_fatal) (const char *fmt, ...) __attribute__ ((noreturn)); + void EXPORT_FUNC(grub_error_push) (void); + int EXPORT_FUNC(grub_error_pop) (void); +diff --git a/include/grub/fdt.h b/include/grub/fdt.h +index e609c7e41..3514aa4a5 100644 +--- a/include/grub/fdt.h ++++ b/include/grub/fdt.h +@@ -19,6 +19,9 @@ + #ifndef GRUB_FDT_HEADER + #define GRUB_FDT_HEADER 1 + ++#if !defined(GRUB_MACHINE_EMU) && \ ++ (defined(__arm__) || defined(__aarch64__) || defined(__riscv)) ++ + #include + #include + +@@ -144,4 +147,7 @@ int EXPORT_FUNC(grub_fdt_set_prop) (void *fdt, unsigned int nodeoffset, const ch + grub_fdt_set_prop ((fdt), (nodeoffset), "reg", reg_64, 16); \ + }) + ++#endif /* !defined(GRUB_MACHINE_EMU) && \ ++ (defined(__arm__) || defined(__aarch64__) || defined(__riscv)) */ ++ + #endif /* ! GRUB_FDT_HEADER */ +diff --git a/include/grub/file.h b/include/grub/file.h +index a5bf3a792..d678de063 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -80,6 +80,8 @@ enum grub_file_type + GRUB_FILE_TYPE_PUBLIC_KEY, + /* File holding public key to add to trused keys. */ + GRUB_FILE_TYPE_PUBLIC_KEY_TRUST, ++ /* File holding x509 certificiate to add to trusted keys. */ ++ GRUB_FILE_TYPE_CERTIFICATE_TRUST, + /* File of which we intend to print a blocklist to the user. */ + GRUB_FILE_TYPE_PRINT_BLOCKLIST, + /* File we intend to use for test loading or testing speed. */ +diff --git a/include/grub/gcrypt/.gitignore b/include/grub/gcrypt/.gitignore +new file mode 100644 +index 000000000..8fbf56462 +--- /dev/null ++++ b/include/grub/gcrypt/.gitignore +@@ -0,0 +1,2 @@ ++g10lib.h ++gcrypt.h +diff --git a/include/grub/i386/efi/console.h b/include/grub/i386/efi/console.h +new file mode 100644 +index 000000000..9231375cb +--- /dev/null ++++ b/include/grub/i386/efi/console.h +@@ -0,0 +1,24 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_I386_EFI_CONSOLE_H ++#define GRUB_I386_EFI_CONSOLE_H ++ ++#include ++ ++#endif /* ! GRUB_I386_EFI_CONSOLE_H */ +diff --git a/include/grub/i386/efi/memory.h b/include/grub/i386/efi/memory.h +index 2c64918e3..a4c2ec835 100644 +--- a/include/grub/i386/efi/memory.h ++++ b/include/grub/i386/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h +index d4b550869..461097781 100644 +--- a/include/grub/i386/linux.h ++++ b/include/grub/i386/linux.h +@@ -148,6 +148,11 @@ struct linux_i386_kernel_header + grub_uint32_t kernel_alignment; + grub_uint8_t relocatable; + grub_uint8_t min_alignment; ++#define LINUX_XLF_KERNEL_64 (1<<0) ++#define LINUX_XLF_CAN_BE_LOADED_ABOVE_4G (1<<1) ++#define LINUX_XLF_EFI_HANDOVER_32 (1<<2) ++#define LINUX_XLF_EFI_HANDOVER_64 (1<<3) ++#define LINUX_XLF_EFI_KEXEC (1<<4) + grub_uint16_t xloadflags; + grub_uint32_t cmdline_size; + grub_uint32_t hardware_subarch; +@@ -241,7 +246,11 @@ struct linux_kernel_params + grub_uint32_t ofw_cif_handler; /* b8 */ + grub_uint32_t ofw_idt; /* bc */ + +- grub_uint8_t padding7[0x1b8 - 0xc0]; ++ grub_uint32_t ext_ramdisk_image; /* 0xc0 */ ++ grub_uint32_t ext_ramdisk_size; /* 0xc4 */ ++ grub_uint32_t ext_cmd_line_ptr; /* 0xc8 */ ++ ++ grub_uint8_t padding7[0x1b8 - 0xcc]; + + union + { +diff --git a/include/grub/ia64/efi/memory.h b/include/grub/ia64/efi/memory.h +index 2c64918e3..a4c2ec835 100644 +--- a/include/grub/ia64/efi/memory.h ++++ b/include/grub/ia64/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/ia64/linux.h b/include/grub/ia64/linux.h +new file mode 100644 +index 000000000..e69de29bb +diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h +index dddb38514..db0ec5f4c 100644 +--- a/include/grub/ieee1275/ieee1275.h ++++ b/include/grub/ieee1275/ieee1275.h +@@ -145,6 +145,8 @@ enum grub_ieee1275_flag + GRUB_IEEE1275_FLAG_POWER_VM, + + GRUB_IEEE1275_FLAG_POWER_KVM, ++ ++ GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT + }; + + extern int EXPORT_FUNC(grub_ieee1275_test_flag) (enum grub_ieee1275_flag flag); +@@ -251,6 +253,8 @@ int EXPORT_FUNC(grub_ieee1275_devalias_next) (struct grub_ieee1275_devalias *ali + void EXPORT_FUNC(grub_ieee1275_children_peer) (struct grub_ieee1275_devalias *alias); + void EXPORT_FUNC(grub_ieee1275_children_first) (const char *devpath, + struct grub_ieee1275_devalias *alias); ++int EXPORT_FUNC(grub_ieee1275_cas_reboot) (char *script); ++int EXPORT_FUNC(grub_ieee1275_set_boot_last_label) (const char *text); + + char *EXPORT_FUNC(grub_ieee1275_get_boot_dev) (void); + +diff --git a/include/grub/ieee1275/ofdisk.h b/include/grub/ieee1275/ofdisk.h +index 2f69e3f19..0074d55ee 100644 +--- a/include/grub/ieee1275/ofdisk.h ++++ b/include/grub/ieee1275/ofdisk.h +@@ -22,4 +22,17 @@ + extern void grub_ofdisk_init (void); + extern void grub_ofdisk_fini (void); + ++#define MAX_RETRIES 20 ++ ++ ++#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) \ ++ unsigned max_retries = MAX_RETRIES; \ ++ if(grub_env_get("ofdisk_retries") != NULL) \ ++ max_retries = grub_strtoul(grub_env_get("ofdisk_retries"), 0, 10)+1; \ ++ grub_dprintf("ofdisk","MAX_RETRIES set to %u\n",max_retries); \ ++ unsigned retry_i=0;for(retry_i=0; retry_i < max_retries; retry_i++){ \ ++ if(!grub_ieee1275_open(device, last_ihandle)) \ ++ break; \ ++ grub_dprintf("ofdisk","Opening disk %s failed. Retrying...\n",device); } ++ + #endif /* ! GRUB_INIT_HEADER */ +diff --git a/include/grub/kernel.h b/include/grub/kernel.h +index abbca5ea3..98edc0863 100644 +--- a/include/grub/kernel.h ++++ b/include/grub/kernel.h +@@ -30,7 +30,9 @@ enum + OBJ_TYPE_PREFIX, + OBJ_TYPE_PUBKEY, + OBJ_TYPE_DTB, +- OBJ_TYPE_DISABLE_SHIM_LOCK ++ OBJ_TYPE_DISABLE_SHIM_LOCK, ++ OBJ_TYPE_GPG_PUBKEY, ++ OBJ_TYPE_X509_PUBKEY, + }; + + /* The module header. */ +@@ -111,6 +113,11 @@ grub_addr_t grub_modules_get_end (void); + + #endif + ++#if !defined(GRUB_MACHINE_EMU) ++void EXPORT_FUNC(start) (void); ++void EXPORT_FUNC(_start) (void); ++#endif ++ + /* The start point of the C code. */ + void grub_main (void) __attribute__ ((noreturn)); + +diff --git a/include/grub/lib/envblk.h b/include/grub/lib/envblk.h +index c3e655921..ab969af24 100644 +--- a/include/grub/lib/envblk.h ++++ b/include/grub/lib/envblk.h +@@ -22,6 +22,8 @@ + #define GRUB_ENVBLK_SIGNATURE "# GRUB Environment Block\n" + #define GRUB_ENVBLK_DEFCFG "grubenv" + ++#define DEFAULT_ENVBLK_SIZE 1024 ++ + #ifndef ASM_FILE + + struct grub_envblk +@@ -33,6 +35,7 @@ typedef struct grub_envblk *grub_envblk_t; + + grub_envblk_t grub_envblk_open (char *buf, grub_size_t size); + int grub_envblk_set (grub_envblk_t envblk, const char *name, const char *value); ++grub_err_t grub_envblk_get (grub_envblk_t envblk, const char * const name, char ** const value); + void grub_envblk_delete (grub_envblk_t envblk, const char *name); + void grub_envblk_iterate (grub_envblk_t envblk, + void *hook_data, +diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h +new file mode 100644 +index 000000000..28dbf16c4 +--- /dev/null ++++ b/include/grub/libtasn1.h +@@ -0,0 +1,589 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * LIBTASN1 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.1 of ++ * the License, or (at your option) any later version. ++ * ++ * LIBTASN1 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 LIBTASN1; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ * ++ */ ++ ++/** ++ * libtasn1:Short_Description: ++ * ++ * GNU ASN.1 library ++ */ ++/** ++ * libtasn1:Long_Description: ++ * ++ * The Libtasn1 library provides Abstract Syntax Notation One (ASN.1, as ++ * specified by the X.680 ITU-T recommendation) parsing and structures ++ * management, and Distinguished Encoding Rules (DER, as per X.690) ++ * encoding and decoding functions. ++ */ ++ ++ ++#ifndef LIBTASN1_H ++#define LIBTASN1_H ++ ++/* grub: ASN1_API is not used */ ++#define ASN1_API ++ ++/* grub: all our supported compilers support these attributes */ ++#define __LIBTASN1_CONST__ __attribute__((const)) ++#define __LIBTASN1_PURE__ __attribute__((pure)) ++ ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++/** ++ * ASN1_VERSION: ++ * ++ * Version of the library as a string. ++ */ ++#define ASN1_VERSION "4.16.0" ++ ++/** ++ * ASN1_VERSION_MAJOR: ++ * ++ * Major version number of the library. ++ */ ++#define ASN1_VERSION_MAJOR 4 ++ ++/** ++ * ASN1_VERSION_MINOR: ++ * ++ * Minor version number of the library. ++ */ ++#define ASN1_VERSION_MINOR 16 ++ ++/** ++ * ASN1_VERSION_PATCH: ++ * ++ * Patch version number of the library. ++ */ ++#define ASN1_VERSION_PATCH 0 ++ ++/** ++ * ASN1_VERSION_NUMBER: ++ * ++ * Version number of the library as a number. ++ */ ++#define ASN1_VERSION_NUMBER 0x041000 ++ ++ ++#if defined __GNUC__ && !defined ASN1_INTERNAL_BUILD ++# define _ASN1_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) ++# if _ASN1_GCC_VERSION >= 30100 ++# define _ASN1_GCC_ATTR_DEPRECATED __attribute__ ((__deprecated__)) ++# endif ++#endif ++ ++#ifndef _ASN1_GCC_ATTR_DEPRECATED ++#define _ASN1_GCC_ATTR_DEPRECATED ++#endif ++ ++/*****************************************/ ++/* Errors returned by libtasn1 functions */ ++/*****************************************/ ++#define ASN1_SUCCESS 0 ++#define ASN1_FILE_NOT_FOUND 1 ++#define ASN1_ELEMENT_NOT_FOUND 2 ++#define ASN1_IDENTIFIER_NOT_FOUND 3 ++#define ASN1_DER_ERROR 4 ++#define ASN1_VALUE_NOT_FOUND 5 ++#define ASN1_GENERIC_ERROR 6 ++#define ASN1_VALUE_NOT_VALID 7 ++#define ASN1_TAG_ERROR 8 ++#define ASN1_TAG_IMPLICIT 9 ++#define ASN1_ERROR_TYPE_ANY 10 ++#define ASN1_SYNTAX_ERROR 11 ++#define ASN1_MEM_ERROR 12 ++#define ASN1_MEM_ALLOC_ERROR 13 ++#define ASN1_DER_OVERFLOW 14 ++#define ASN1_NAME_TOO_LONG 15 ++#define ASN1_ARRAY_ERROR 16 ++#define ASN1_ELEMENT_NOT_EMPTY 17 ++#define ASN1_TIME_ENCODING_ERROR 18 ++#define ASN1_RECURSION 19 ++ ++/*************************************/ ++/* Constants used in asn1_visit_tree */ ++/*************************************/ ++#define ASN1_PRINT_NAME 1 ++#define ASN1_PRINT_NAME_TYPE 2 ++#define ASN1_PRINT_NAME_TYPE_VALUE 3 ++#define ASN1_PRINT_ALL 4 ++ ++/*****************************************/ ++/* Constants returned by asn1_read_tag */ ++/*****************************************/ ++#define ASN1_CLASS_UNIVERSAL 0x00 /* old: 1 */ ++#define ASN1_CLASS_APPLICATION 0x40 /* old: 2 */ ++#define ASN1_CLASS_CONTEXT_SPECIFIC 0x80 /* old: 3 */ ++#define ASN1_CLASS_PRIVATE 0xC0 /* old: 4 */ ++#define ASN1_CLASS_STRUCTURED 0x20 ++ ++/*****************************************/ ++/* Constants returned by asn1_read_tag */ ++/*****************************************/ ++#define ASN1_TAG_BOOLEAN 0x01 ++#define ASN1_TAG_INTEGER 0x02 ++#define ASN1_TAG_SEQUENCE 0x10 ++#define ASN1_TAG_SET 0x11 ++#define ASN1_TAG_OCTET_STRING 0x04 ++#define ASN1_TAG_BIT_STRING 0x03 ++#define ASN1_TAG_UTCTime 0x17 ++#define ASN1_TAG_GENERALIZEDTime 0x18 ++#define ASN1_TAG_OBJECT_ID 0x06 ++#define ASN1_TAG_ENUMERATED 0x0A ++#define ASN1_TAG_NULL 0x05 ++#define ASN1_TAG_GENERALSTRING 0x1B ++#define ASN1_TAG_NUMERIC_STRING 0x12 ++#define ASN1_TAG_IA5_STRING 0x16 ++#define ASN1_TAG_TELETEX_STRING 0x14 ++#define ASN1_TAG_PRINTABLE_STRING 0x13 ++#define ASN1_TAG_UNIVERSAL_STRING 0x1C ++#define ASN1_TAG_BMP_STRING 0x1E ++#define ASN1_TAG_UTF8_STRING 0x0C ++#define ASN1_TAG_VISIBLE_STRING 0x1A ++ ++/** ++ * asn1_node: ++ * ++ * Structure definition used for the node of the tree ++ * that represents an ASN.1 DEFINITION. ++ */ ++typedef struct asn1_node_st asn1_node_st; ++ ++typedef asn1_node_st *asn1_node; ++typedef const asn1_node_st *asn1_node_const; ++ ++/** ++ * ASN1_MAX_NAME_SIZE: ++ * ++ * Maximum number of characters of a name ++ * inside a file with ASN1 definitions. ++ */ ++#define ASN1_MAX_NAME_SIZE 64 ++ ++ ++/** ++ * asn1_static_node: ++ * @name: Node name ++ * @type: Node typ ++ * @value: Node value ++ * ++ * For the on-disk format of ASN.1 trees, created by asn1_parser2array(). ++ */ ++struct asn1_static_node_st ++{ ++ const char *name; /* Node name */ ++ unsigned int type; /* Node type */ ++ const void *value; /* Node value */ ++}; ++typedef struct asn1_static_node_st asn1_static_node; ++ ++/* List of constants for field type of node_asn */ ++#define ASN1_ETYPE_INVALID 0 ++#define ASN1_ETYPE_CONSTANT 1 ++#define ASN1_ETYPE_IDENTIFIER 2 ++#define ASN1_ETYPE_INTEGER 3 ++#define ASN1_ETYPE_BOOLEAN 4 ++#define ASN1_ETYPE_SEQUENCE 5 ++#define ASN1_ETYPE_BIT_STRING 6 ++#define ASN1_ETYPE_OCTET_STRING 7 ++#define ASN1_ETYPE_TAG 8 ++#define ASN1_ETYPE_DEFAULT 9 ++#define ASN1_ETYPE_SIZE 10 ++#define ASN1_ETYPE_SEQUENCE_OF 11 ++#define ASN1_ETYPE_OBJECT_ID 12 ++#define ASN1_ETYPE_ANY 13 ++#define ASN1_ETYPE_SET 14 ++#define ASN1_ETYPE_SET_OF 15 ++#define ASN1_ETYPE_DEFINITIONS 16 ++#define ASN1_ETYPE_CHOICE 18 ++#define ASN1_ETYPE_IMPORTS 19 ++#define ASN1_ETYPE_NULL 20 ++#define ASN1_ETYPE_ENUMERATED 21 ++#define ASN1_ETYPE_GENERALSTRING 27 ++#define ASN1_ETYPE_NUMERIC_STRING 28 ++#define ASN1_ETYPE_IA5_STRING 29 ++#define ASN1_ETYPE_TELETEX_STRING 30 ++#define ASN1_ETYPE_PRINTABLE_STRING 31 ++#define ASN1_ETYPE_UNIVERSAL_STRING 32 ++#define ASN1_ETYPE_BMP_STRING 33 ++#define ASN1_ETYPE_UTF8_STRING 34 ++#define ASN1_ETYPE_VISIBLE_STRING 35 ++#define ASN1_ETYPE_UTC_TIME 36 ++#define ASN1_ETYPE_GENERALIZED_TIME 37 ++ ++/** ++ * ASN1_DELETE_FLAG_ZEROIZE: ++ * ++ * Used by: asn1_delete_structure2() ++ * ++ * Zeroize values prior to deinitialization. ++ */ ++#define ASN1_DELETE_FLAG_ZEROIZE 1 ++ ++/** ++ * ASN1_DECODE_FLAG_ALLOW_PADDING: ++ * ++ * Used by: asn1_der_decoding2() ++ * ++ * This flag would allow arbitrary data past the DER data. ++ */ ++#define ASN1_DECODE_FLAG_ALLOW_PADDING 1 ++/** ++ * ASN1_DECODE_FLAG_STRICT_DER: ++ * ++ * Used by: asn1_der_decoding2() ++ * ++ * This flag would ensure that no BER decoding takes place. ++ */ ++#define ASN1_DECODE_FLAG_STRICT_DER (1<<1) ++/** ++ * ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME: ++ * ++ * Used by: asn1_der_decoding2() ++ * ++ * This flag will tolerate Time encoding errors when in strict DER. ++ */ ++#define ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME (1<<2) ++ ++ ++/** ++ * asn1_data_node_st: ++ * @name: Node name ++ * @value: Node value ++ * @value_len: Node value size ++ * @type: Node value type (ASN1_ETYPE_*) ++ * ++ * Data node inside a #asn1_node structure. ++ */ ++struct asn1_data_node_st ++{ ++ const char *name; /* Node name */ ++ const void *value; /* Node value */ ++ unsigned int value_len; /* Node value size */ ++ unsigned int type; /* Node value type (ASN1_ETYPE_*) */ ++}; ++typedef struct asn1_data_node_st asn1_data_node_st; ++ ++/***********************************/ ++/* Fixed constants */ ++/***********************************/ ++ ++/** ++ * ASN1_MAX_ERROR_DESCRIPTION_SIZE: ++ * ++ * Maximum number of characters ++ * of a description message ++ * (null character included). ++ */ ++#define ASN1_MAX_ERROR_DESCRIPTION_SIZE 128 ++ ++/***********************************/ ++/* Functions definitions */ ++/***********************************/ ++ ++/* These functions are not used in grub and should not be referenced. */ ++#if 0 ++extern ASN1_API int ++ asn1_parser2tree (const char *file, ++ asn1_node * definitions, char *error_desc); ++ ++extern ASN1_API int ++ asn1_parser2array (const char *inputFileName, ++ const char *outputFileName, ++ const char *vectorName, char *error_desc); ++#endif ++ ++extern ASN1_API int ++ asn1_array2tree (const asn1_static_node * array, ++ asn1_node * definitions, char *errorDescription); ++ ++#if 0 ++extern ASN1_API void ++ asn1_print_structure (FILE * out, asn1_node_const structure, ++ const char *name, int mode); ++#endif ++ ++extern ASN1_API int ++ asn1_create_element (asn1_node_const definitions, ++ const char *source_name, asn1_node * element); ++ ++extern ASN1_API int asn1_delete_structure (asn1_node * structure); ++ ++extern ASN1_API int asn1_delete_structure2 (asn1_node * structure, unsigned int flags); ++ ++extern ASN1_API int ++ asn1_delete_element (asn1_node structure, const char *element_name); ++ ++#if 0 ++extern ASN1_API int ++ asn1_write_value (asn1_node node_root, const char *name, ++ const void *ivalue, int len); ++#endif ++ ++extern ASN1_API int ++ asn1_read_value (asn1_node_const root, const char *name, ++ void *ivalue, int *len); ++ ++extern ASN1_API int ++ asn1_read_value_type (asn1_node_const root, const char *name, ++ void *ivalue, int *len, unsigned int *etype); ++ ++extern ASN1_API int ++ asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data); ++ ++extern ASN1_API int ++ asn1_number_of_elements (asn1_node_const element, const char *name, int *num); ++ ++#if 0 ++extern ASN1_API int ++ asn1_der_coding (asn1_node_const element, const char *name, ++ void *ider, int *len, char *ErrorDescription); ++#endif ++ ++extern ASN1_API int ++ asn1_der_decoding2 (asn1_node *element, const void *ider, ++ int *max_ider_len, unsigned int flags, ++ char *errorDescription); ++ ++extern ASN1_API int ++ asn1_der_decoding (asn1_node * element, const void *ider, ++ int ider_len, char *errorDescription); ++ ++#if 0 ++/* Do not use. Use asn1_der_decoding() instead. */ ++extern ASN1_API int ++ asn1_der_decoding_element (asn1_node * structure, ++ const char *elementName, ++ const void *ider, int len, ++ char *errorDescription) _ASN1_GCC_ATTR_DEPRECATED; ++#endif ++ ++extern ASN1_API int ++ asn1_der_decoding_startEnd (asn1_node element, ++ const void *ider, int ider_len, ++ const char *name_element, ++ int *start, int *end); ++ ++extern ASN1_API int ++ asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element); ++ ++extern ASN1_API int ++ asn1_expand_octet_string (asn1_node_const definitions, ++ asn1_node * element, ++ const char *octetName, const char *objectName); ++ ++extern ASN1_API int ++ asn1_read_tag (asn1_node_const root, const char *name, ++ int *tagValue, int *classValue); ++ ++extern ASN1_API const char *asn1_find_structure_from_oid (asn1_node_const ++ definitions, ++ const char ++ *oidValue); ++ ++#if 0 ++__LIBTASN1_PURE__ ++extern ASN1_API const char *asn1_check_version (const char *req_version); ++#endif ++ ++__LIBTASN1_PURE__ ++extern ASN1_API const char *asn1_strerror (int error); ++ ++#if 0 ++extern ASN1_API void asn1_perror (int error); ++#endif ++ ++#define ASN1_MAX_TAG_SIZE 4 ++#define ASN1_MAX_LENGTH_SIZE 9 ++#define ASN1_MAX_TL_SIZE (ASN1_MAX_TAG_SIZE+ASN1_MAX_LENGTH_SIZE) ++extern ASN1_API long ++ asn1_get_length_der (const unsigned char *der, int der_len, int *len); ++ ++extern ASN1_API long ++ asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len); ++ ++extern ASN1_API void ++ asn1_length_der (unsigned long int len, unsigned char *der, int *der_len); ++ ++/* Other utility functions. */ ++ ++extern ASN1_API ++ int asn1_decode_simple_der (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, ++ const unsigned char **str, ++ unsigned int *str_len); ++ ++extern ASN1_API ++ int asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, ++ unsigned char **str, ++ unsigned int *str_len, ++ unsigned int *ber_len); ++ ++extern ASN1_API int ++ asn1_encode_simple_der (unsigned int etype, const unsigned char *str, ++ unsigned int str_len, unsigned char *tl, ++ unsigned int *tl_len); ++ ++extern ASN1_API asn1_node ++ asn1_find_node (asn1_node_const pointer, const char *name); ++ ++extern ASN1_API int ++ asn1_copy_node (asn1_node dst, const char *dst_name, ++ asn1_node_const src, const char *src_name); ++extern ASN1_API asn1_node ++ asn1_dup_node (asn1_node_const src, const char *src_name); ++ ++/* Internal and low-level DER utility functions. */ ++ ++extern ASN1_API int ++ asn1_get_tag_der (const unsigned char *der, int der_len, ++ unsigned char *cls, int *len, unsigned long *tag); ++ ++extern ASN1_API void ++ asn1_octet_der (const unsigned char *str, int str_len, ++ unsigned char *der, int *der_len); ++ ++extern ASN1_API int ++ asn1_get_octet_der (const unsigned char *der, int der_len, ++ int *ret_len, unsigned char *str, ++ int str_size, int *str_len); ++ ++extern ASN1_API void asn1_bit_der (const unsigned char *str, int bit_len, ++ unsigned char *der, int *der_len); ++ ++extern ASN1_API int ++ asn1_get_bit_der (const unsigned char *der, int der_len, ++ int *ret_len, unsigned char *str, ++ int str_size, int *bit_len); ++ ++extern ASN1_API int ++ asn1_get_object_id_der (const unsigned char *der, ++ int der_len, int *ret_len, ++ char *str, int str_size); ++ ++extern ASN1_API int ++ asn1_object_id_der (const char *str, unsigned char *der, int *der_len, ++ unsigned flags); ++ ++/* Compatibility types */ ++ ++/** ++ * asn1_retCode: ++ * ++ * Type formerly returned by libtasn1 functions. ++ * ++ * Deprecated: 3.0: Use int instead. ++ */ ++typedef int asn1_retCode; ++ ++/** ++ * node_asn_struct: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_node instead. ++ */ ++#define node_asn_struct asn1_node_st ++ ++/** ++ * node_asn: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_node instead. ++ */ ++#define node_asn asn1_node_st ++ ++/** ++ * ASN1_TYPE: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_node instead. ++ */ ++#define ASN1_TYPE asn1_node ++ ++/** ++ * ASN1_TYPE_EMPTY: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use NULL instead. ++ */ ++#define ASN1_TYPE_EMPTY NULL ++ ++/** ++ * static_struct_asn: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_static_node instead. ++ */ ++#define static_struct_asn asn1_static_node_st ++ ++/** ++ * ASN1_ARRAY_TYPE: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_static_node instead. ++ */ ++#define ASN1_ARRAY_TYPE asn1_static_node ++ ++/** ++ * asn1_static_node_t: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_static_node instead. ++ */ ++#define asn1_static_node_t asn1_static_node ++ ++/** ++ * node_data_struct: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_data_node_st instead. ++ */ ++#define node_data_struct asn1_data_node_st ++ ++/** ++ * ASN1_DATA_NODE: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_data_node_st instead. ++ */ ++#define ASN1_DATA_NODE asn1_data_node_st ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* LIBTASN1_H */ +diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h +index 40531fa82..ebfee4bf0 100644 +--- a/include/grub/lockdown.h ++++ b/include/grub/lockdown.h +@@ -24,7 +24,8 @@ + #define GRUB_LOCKDOWN_DISABLED 0 + #define GRUB_LOCKDOWN_ENABLED 1 + +-#ifdef GRUB_MACHINE_EFI ++#if defined(GRUB_MACHINE_EFI) || \ ++ (defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275)) + extern void + EXPORT_FUNC (grub_lockdown) (void); + extern int +diff --git a/include/grub/loopback.h b/include/grub/loopback.h +new file mode 100644 +index 000000000..3b9a9e32e +--- /dev/null ++++ b/include/grub/loopback.h +@@ -0,0 +1,30 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2019 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_LOOPBACK_HEADER ++#define GRUB_LOOPBACK_HEADER 1 ++ ++struct grub_loopback ++{ ++ char *devname; ++ grub_file_t file; ++ struct grub_loopback *next; ++ unsigned long id; ++}; ++ ++#endif /* ! GRUB_LOOPBACK_HEADER */ +diff --git a/include/grub/menu.h b/include/grub/menu.h +index ee2b5e910..0acdc2aa6 100644 +--- a/include/grub/menu.h ++++ b/include/grub/menu.h +@@ -20,6 +20,16 @@ + #ifndef GRUB_MENU_HEADER + #define GRUB_MENU_HEADER 1 + ++struct bls_entry ++{ ++ struct bls_entry *next; ++ struct bls_entry *prev; ++ struct keyval **keyvals; ++ int nkeyvals; ++ char *filename; ++ int visible; ++}; ++ + struct grub_menu_entry_class + { + char *name; +@@ -60,6 +70,9 @@ struct grub_menu_entry + + /* The next element. */ + struct grub_menu_entry *next; ++ ++ /* BLS used to populate the entry */ ++ struct bls_entry *bls; + }; + typedef struct grub_menu_entry *grub_menu_entry_t; + +diff --git a/include/grub/mips/linux.h b/include/grub/mips/linux.h +new file mode 100644 +index 000000000..e69de29bb +diff --git a/include/grub/misc.h b/include/grub/misc.h +index 1b35a167f..db517acd5 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -35,6 +35,14 @@ + #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) + #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; } + ++#ifndef CONCAT_ ++#define CONCAT_(a, b) a ## b ++#endif ++ ++#ifndef CONCAT ++#define CONCAT(a, b) CONCAT_(a, b) ++#endif ++ + #define grub_dprintf(condition, ...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, __VA_ARGS__) + + void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t n); +@@ -335,6 +343,7 @@ char *EXPORT_FUNC(grub_strdup) (const char *s) WARN_UNUSED_RESULT; + char *EXPORT_FUNC(grub_strndup) (const char *s, grub_size_t n) WARN_UNUSED_RESULT; + void *EXPORT_FUNC(grub_memset) (void *s, int c, grub_size_t n); + grub_size_t EXPORT_FUNC(grub_strlen) (const char *s) WARN_UNUSED_RESULT; ++void EXPORT_FUNC(grub_str_sep) (const char *s, char *p, char delim, char *r); + + /* Replace all `ch' characters of `input' with `with' and copy the + result into `output'; return EOS address of `output'. */ +@@ -369,6 +378,7 @@ grub_puts (const char *s) + } + + int EXPORT_FUNC(grub_puts_) (const char *s); ++int EXPORT_FUNC(grub_debug_is_enabled) (void); + int EXPORT_FUNC(grub_debug_enabled) (const char *condition); + void EXPORT_FUNC(grub_real_dprintf) (const char *file, + const int line, +@@ -376,6 +386,8 @@ void EXPORT_FUNC(grub_real_dprintf) (const char *file, + const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 4, 5))); + int EXPORT_FUNC(grub_printf) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2))); + int EXPORT_FUNC(grub_printf_) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2))); ++void EXPORT_FUNC(grub_qdprintf) (const char *condition, ++ const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 2, 3))); + int EXPORT_FUNC(grub_vprintf) (const char *fmt, va_list args); + int EXPORT_FUNC(grub_snprintf) (char *str, grub_size_t n, const char *fmt, ...) + __attribute__ ((format (GNU_PRINTF, 3, 4))); +@@ -385,7 +397,7 @@ char *EXPORT_FUNC(grub_xasprintf) (const char *fmt, ...) + __attribute__ ((format (GNU_PRINTF, 1, 2))) WARN_UNUSED_RESULT; + char *EXPORT_FUNC(grub_xvasprintf) (const char *fmt, va_list args) WARN_UNUSED_RESULT; + +-void EXPORT_FUNC(grub_exit) (void) __attribute__ ((noreturn)); ++void EXPORT_FUNC(grub_exit) (int rc) __attribute__ ((noreturn)); + void EXPORT_FUNC(grub_abort) (void) __attribute__ ((noreturn)); + grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n, + grub_uint64_t d, +@@ -521,11 +533,24 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file, + const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 3, 4))); + #define grub_boot_time(...) grub_real_boot_time(GRUB_FILE, __LINE__, __VA_ARGS__) + #else +-#define grub_boot_time(...) ++#define grub_boot_time(fmt, ...) grub_dprintf("boot", fmt "\n", ##__VA_ARGS__) + #endif + +-#define grub_max(a, b) (((a) > (b)) ? (a) : (b)) +-#define grub_min(a, b) (((a) < (b)) ? (a) : (b)) ++#define _grub_min(a, b, _a, _b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a < _b ? _a : _b; }) ++#define grub_min(a, b) _grub_min(a, b, \ ++ CONCAT(_a_,__COUNTER__), \ ++ CONCAT(_b_,__COUNTER__)) ++ ++#define _grub_max(a, b, _a, _b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a > _b ? _a : _b; }) ++#define grub_max(a, b) _grub_max(a, b, \ ++ CONCAT(_a_,__COUNTER__), \ ++ CONCAT(_b_,__COUNTER__)) + + #define grub_log2ull(n) (GRUB_TYPE_BITS (grub_uint64_t) - __builtin_clzll (n) - 1) + +diff --git a/include/grub/mm.h b/include/grub/mm.h +index f3bf87fa0..8ee1fc717 100644 +--- a/include/grub/mm.h ++++ b/include/grub/mm.h +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + + #ifndef NULL +@@ -56,6 +57,37 @@ void *EXPORT_FUNC(grub_realloc) (void *ptr, grub_size_t size); + void *EXPORT_FUNC(grub_memalign) (grub_size_t align, grub_size_t size); + #endif + ++#define GRUB_MEM_ATTR_R 0x0000000000000004LLU ++#define GRUB_MEM_ATTR_W 0x0000000000000002LLU ++#define GRUB_MEM_ATTR_X 0x0000000000000001LLU ++ ++#ifdef GRUB_MACHINE_EFI ++grub_err_t EXPORT_FUNC(grub_get_mem_attrs) (grub_addr_t addr, ++ grub_size_t size, ++ grub_uint64_t *attrs); ++grub_err_t EXPORT_FUNC(grub_update_mem_attrs) (grub_addr_t addr, ++ grub_size_t size, ++ grub_uint64_t set_attrs, ++ grub_uint64_t clear_attrs); ++#else /* !GRUB_MACHINE_EFI */ ++static inline grub_err_t ++grub_get_mem_attrs (grub_addr_t addr __attribute__((__unused__)), ++ grub_size_t size __attribute__((__unused__)), ++ grub_uint64_t *attrs __attribute__((__unused__))) ++{ ++ return GRUB_ERR_NONE; ++} ++ ++static inline grub_err_t ++grub_update_mem_attrs (grub_addr_t addr __attribute__((__unused__)), ++ grub_size_t size __attribute__((__unused__)), ++ grub_uint64_t set_attrs __attribute__((__unused__)), ++ grub_uint64_t clear_attrs __attribute__((__unused__))) ++{ ++ return GRUB_ERR_NONE; ++} ++#endif /* GRUB_MACHINE_EFI */ ++ + void grub_mm_check_real (const char *file, int line); + #define grub_mm_check() grub_mm_check_real (GRUB_FILE, __LINE__); + +diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h +index 96c2d816b..2481ee1fa 100644 +--- a/include/grub/mm_private.h ++++ b/include/grub/mm_private.h +@@ -20,7 +20,6 @@ + #define GRUB_MM_PRIVATE_H 1 + + #include +-#include + + /* For context, see kern/mm.c */ + +@@ -99,17 +98,4 @@ typedef struct grub_mm_region + extern grub_mm_region_t EXPORT_VAR (grub_mm_base); + #endif + +-static inline void +-grub_mm_size_sanity_check (void) { +- /* Ensure we preserve alignment when doing h = (grub_mm_header_t) (r + 1). */ +- COMPILE_TIME_ASSERT ((sizeof (struct grub_mm_region) % +- sizeof (struct grub_mm_header)) == 0); +- +- /* +- * GRUB_MM_ALIGN is supposed to represent cell size, and a mm_header is +- * supposed to be 1 cell. +- */ +- COMPILE_TIME_ASSERT (sizeof (struct grub_mm_header) == GRUB_MM_ALIGN); +-} +- + #endif +diff --git a/include/grub/net.h b/include/grub/net.h +index 844e501c1..868c9a2ef 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -29,7 +29,8 @@ + + enum + { +- GRUB_NET_MAX_LINK_HEADER_SIZE = 64, ++ GRUB_NET_MAX_LINK_HEADER_SIZE = 96, ++ GRUB_NET_MAX_LINK_ADDRESS_SIZE = 32, + GRUB_NET_UDP_HEADER_SIZE = 8, + GRUB_NET_TCP_HEADER_SIZE = 20, + GRUB_NET_OUR_IPV4_HEADER_SIZE = 20, +@@ -42,15 +43,17 @@ enum + + typedef enum grub_link_level_protocol_id + { +- GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET ++ /* IANA ARP constant to define hardware type. */ ++ GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET = 1, + } grub_link_level_protocol_id_t; + + typedef struct grub_net_link_level_address + { + grub_link_level_protocol_id_t type; ++ grub_uint8_t len; + union + { +- grub_uint8_t mac[6]; ++ grub_uint8_t mac[GRUB_NET_MAX_LINK_ADDRESS_SIZE]; + }; + } grub_net_link_level_address_t; + +@@ -450,6 +453,66 @@ struct grub_net_bootp_packet + grub_uint8_t vendor[0]; + } GRUB_PACKED; + ++struct grub_net_dhcp6_packet ++{ ++ grub_uint32_t message_type:8; ++ grub_uint32_t transaction_id:24; ++ grub_uint8_t dhcp_options[0]; ++} GRUB_PACKED; ++ ++struct grub_net_dhcp6_option { ++ grub_uint16_t code; ++ grub_uint16_t len; ++ grub_uint8_t data[0]; ++} GRUB_PACKED; ++ ++struct grub_net_dhcp6_option_iana { ++ grub_uint32_t iaid; ++ grub_uint32_t t1; ++ grub_uint32_t t2; ++ grub_uint8_t data[0]; ++} GRUB_PACKED; ++ ++struct grub_net_dhcp6_option_iaaddr { ++ grub_uint8_t addr[16]; ++ grub_uint32_t preferred_lifetime; ++ grub_uint32_t valid_lifetime; ++ grub_uint8_t data[0]; ++} GRUB_PACKED; ++ ++struct grub_net_dhcp6_option_duid_ll ++{ ++ grub_uint16_t type; ++ grub_uint16_t hw_type; ++ grub_uint8_t hwaddr[6]; ++} GRUB_PACKED; ++ ++enum ++ { ++ GRUB_NET_DHCP6_SOLICIT = 1, ++ GRUB_NET_DHCP6_ADVERTISE = 2, ++ GRUB_NET_DHCP6_REQUEST = 3, ++ GRUB_NET_DHCP6_REPLY = 7 ++ }; ++ ++enum ++ { ++ DHCP6_CLIENT_PORT = 546, ++ DHCP6_SERVER_PORT = 547 ++ }; ++ ++enum ++ { ++ GRUB_NET_DHCP6_OPTION_CLIENTID = 1, ++ GRUB_NET_DHCP6_OPTION_SERVERID = 2, ++ GRUB_NET_DHCP6_OPTION_IA_NA = 3, ++ GRUB_NET_DHCP6_OPTION_IAADDR = 5, ++ GRUB_NET_DHCP6_OPTION_ORO = 6, ++ GRUB_NET_DHCP6_OPTION_ELAPSED_TIME = 8, ++ GRUB_NET_DHCP6_OPTION_DNS_SERVERS = 23, ++ GRUB_NET_DHCP6_OPTION_BOOTFILE_URL = 59 ++ }; ++ + #define GRUB_NET_BOOTP_RFC1048_MAGIC_0 0x63 + #define GRUB_NET_BOOTP_RFC1048_MAGIC_1 0x82 + #define GRUB_NET_BOOTP_RFC1048_MAGIC_2 0x53 +@@ -470,6 +533,7 @@ enum + GRUB_NET_DHCP_MESSAGE_TYPE = 53, + GRUB_NET_DHCP_SERVER_IDENTIFIER = 54, + GRUB_NET_DHCP_PARAMETER_REQUEST_LIST = 55, ++ GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER = 60, + GRUB_NET_BOOTP_CLIENT_ID = 61, + GRUB_NET_DHCP_TFTP_SERVER_NAME = 66, + GRUB_NET_DHCP_BOOTFILE_NAME = 67, +@@ -485,6 +549,21 @@ grub_net_configure_by_dhcp_ack (const char *name, + grub_size_t size, + int is_def, char **device, char **path); + ++struct grub_net_network_level_interface * ++grub_net_configure_by_dhcpv6_reply (const char *name, ++ struct grub_net_card *card, ++ grub_net_interface_flags_t flags, ++ const struct grub_net_dhcp6_packet *v6, ++ grub_size_t size, ++ int is_def, char **device, char **path); ++ ++int ++grub_ipv6_get_masksize(grub_uint16_t *mask); ++ ++grub_err_t ++grub_net_add_ipv6_local (struct grub_net_network_level_interface *inf, ++ int mask); ++ + grub_err_t + grub_net_add_ipv4_local (struct grub_net_network_level_interface *inf, + int mask); +@@ -493,6 +572,10 @@ void + grub_net_process_dhcp (struct grub_net_buff *nb, + struct grub_net_network_level_interface *iface); + ++grub_err_t ++grub_net_process_dhcp6 (struct grub_net_buff *nb, ++ struct grub_net_card *card); ++ + int + grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a, + const grub_net_link_level_address_t *b); +@@ -509,11 +592,13 @@ grub_net_addr_cmp (const grub_net_network_level_address_t *a, + #define GRUB_NET_MAX_STR_ADDR_LEN sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX") + + /* +- Currently suppoerted adresses: +- ethernet: XX:XX:XX:XX:XX:XX ++ Up to 32 byte hardware address supported, see GRUB_NET_MAX_LINK_ADDRESS_SIZE + */ +- +-#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof ("XX:XX:XX:XX:XX:XX")) ++#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof (\ ++ "XX:XX:XX:XX:XX:XX:XX:XX:"\ ++ "XX:XX:XX:XX:XX:XX:XX:XX:"\ ++ "XX:XX:XX:XX:XX:XX:XX:XX:"\ ++ "XX:XX:XX:XX:XX:XX:XX:XX")) + + /* Max VLAN id = 4094 */ + #define GRUB_NET_MAX_STR_VLAN_LEN (sizeof ("vlanXXXX")) +diff --git a/include/grub/net/efi.h b/include/grub/net/efi.h +new file mode 100644 +index 000000000..de90d223e +--- /dev/null ++++ b/include/grub/net/efi.h +@@ -0,0 +1,144 @@ ++#ifndef GRUB_NET_EFI_HEADER ++#define GRUB_NET_EFI_HEADER 1 ++ ++#include ++#include ++#include ++#include ++ ++typedef struct grub_efi_net_interface grub_efi_net_interface_t; ++typedef struct grub_efi_net_ip_config grub_efi_net_ip_config_t; ++typedef union grub_efi_net_ip_address grub_efi_net_ip_address_t; ++typedef struct grub_efi_net_ip_manual_address grub_efi_net_ip_manual_address_t; ++ ++struct grub_efi_net_interface ++{ ++ char *name; ++ int prefer_ip6; ++ struct grub_efi_net_device *dev; ++ struct grub_efi_net_io *io; ++ grub_efi_net_ip_config_t *ip_config; ++ int io_type; ++ struct grub_efi_net_interface *next; ++}; ++ ++#define efi_net_interface_get_hw_address(inf) inf->ip_config->get_hw_address (inf->dev) ++#define efi_net_interface_get_address(inf) inf->ip_config->get_address (inf->dev) ++#define efi_net_interface_get_route_table(inf) inf->ip_config->get_route_table (inf->dev) ++#define efi_net_interface_set_address(inf, addr, with_subnet) inf->ip_config->set_address (inf->dev, addr, with_subnet) ++#define efi_net_interface_set_gateway(inf, addr) inf->ip_config->set_gateway (inf->dev, addr) ++#define efi_net_interface_set_dns(inf, addr) inf->ip_config->set_dns (inf->dev, addr) ++ ++struct grub_efi_net_ip_config ++{ ++ char * (*get_hw_address) (struct grub_efi_net_device *dev); ++ char * (*get_address) (struct grub_efi_net_device *dev); ++ char ** (*get_route_table) (struct grub_efi_net_device *dev); ++ grub_efi_net_interface_t * (*best_interface) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address); ++ int (*set_address) (struct grub_efi_net_device *dev, grub_efi_net_ip_manual_address_t *net_ip, int with_subnet); ++ int (*set_gateway) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address); ++ int (*set_dns) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *dns); ++}; ++ ++union grub_efi_net_ip_address ++{ ++ grub_efi_ipv4_address_t ip4; ++ grub_efi_ipv6_address_t ip6; ++}; ++ ++struct grub_efi_net_ip_manual_address ++{ ++ int is_ip6; ++ union ++ { ++ grub_efi_ip4_config2_manual_address_t ip4; ++ grub_efi_ip6_config_manual_address_t ip6; ++ }; ++}; ++ ++struct grub_efi_net_device ++{ ++ grub_efi_handle_t handle; ++ grub_efi_ip4_config2_protocol_t *ip4_config; ++ grub_efi_ip6_config_protocol_t *ip6_config; ++ grub_efi_handle_t http_handle; ++ grub_efi_http_t *http; ++ grub_efi_handle_t ip4_pxe_handle; ++ grub_efi_pxe_t *ip4_pxe; ++ grub_efi_handle_t ip6_pxe_handle; ++ grub_efi_pxe_t *ip6_pxe; ++ grub_efi_handle_t dhcp4_handle; ++ grub_efi_dhcp4_protocol_t *dhcp4; ++ grub_efi_handle_t dhcp6_handle; ++ grub_efi_dhcp6_protocol_t *dhcp6; ++ char *card_name; ++ grub_efi_net_interface_t *net_interfaces; ++ struct grub_efi_net_device *next; ++}; ++ ++struct grub_efi_net_io ++{ ++ void (*configure) (struct grub_efi_net_device *dev, int prefer_ip6); ++ grub_err_t (*open) (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ const char *filename, ++ int type); ++ grub_ssize_t (*read) (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ char *buf, ++ grub_size_t len); ++ grub_err_t (*close) (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file); ++}; ++ ++extern struct grub_efi_net_device *net_devices; ++ ++extern struct grub_efi_net_io io_http; ++extern struct grub_efi_net_io io_pxe; ++ ++extern grub_efi_net_ip_config_t *efi_net_ip4_config; ++extern grub_efi_net_ip_config_t *efi_net_ip6_config; ++ ++char * ++grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address); ++ ++char * ++grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address); ++ ++char * ++grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address); ++ ++int ++grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest); ++ ++int ++grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest); ++ ++char * ++grub_efi_ip6_interface_name (struct grub_efi_net_device *dev); ++ ++char * ++grub_efi_ip4_interface_name (struct grub_efi_net_device *dev); ++ ++grub_efi_net_interface_t * ++grub_efi_net_create_interface (struct grub_efi_net_device *dev, ++ const char *interface_name, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int has_subnet); ++ ++int grub_efi_net_fs_init (void); ++void grub_efi_net_fs_fini (void); ++int grub_efi_net_boot_from_https (void); ++int grub_efi_net_boot_from_opa (void); ++ ++extern grub_command_func_t grub_efi_net_list_routes; ++extern grub_command_func_t grub_efi_net_list_cards; ++extern grub_command_func_t grub_efi_net_list_addrs; ++extern grub_command_func_t grub_efi_net_add_addr; ++extern grub_command_func_t grub_efi_net_bootp; ++extern grub_command_func_t grub_efi_net_bootp6; ++ ++#endif /* ! GRUB_NET_EFI_HEADER */ +diff --git a/include/grub/normal.h b/include/grub/normal.h +index 218cbabcc..8839ad85a 100644 +--- a/include/grub/normal.h ++++ b/include/grub/normal.h +@@ -145,7 +145,7 @@ grub_normal_add_menu_entry (int argc, const char **args, char **classes, + const char *id, + const char *users, const char *hotkey, + const char *prefix, const char *sourcecode, +- int submenu); ++ int submenu, int *index, struct bls_entry *bls); + + grub_err_t + grub_normal_set_password (const char *user, const char *password); +diff --git a/include/grub/offsets.h b/include/grub/offsets.h +index 871e1cd4c..69211aa79 100644 +--- a/include/grub/offsets.h ++++ b/include/grub/offsets.h +@@ -63,7 +63,7 @@ + #define GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR 0x4400 + + #define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ALIGN 4 +-#define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x200000 ++#define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x400000 + + #define GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR 0x80200000 + +diff --git a/include/grub/pkcs1_v15.h b/include/grub/pkcs1_v15.h +new file mode 100644 +index 000000000..5c338c84a +--- /dev/null ++++ b/include/grub/pkcs1_v15.h +@@ -0,0 +1,27 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2013 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++/* ++ * Given a hash value 'hval', of hash specification 'hash', perform ++ * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod' ++ * (See RFC 8017 s 9.2) ++ */ ++gcry_err_code_t ++grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval, ++ const gcry_md_spec_t * hash, gcry_mpi_t mod); ++ +diff --git a/include/grub/powerpc/linux.h b/include/grub/powerpc/linux.h +new file mode 100644 +index 000000000..e69de29bb +diff --git a/include/grub/riscv64/efi/memory.h b/include/grub/riscv64/efi/memory.h +index c6cb32417..acb61dca4 100644 +--- a/include/grub/riscv64/efi/memory.h ++++ b/include/grub/riscv64/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/search.h b/include/grub/search.h +index ffd2411ca..9343c66b1 100644 +--- a/include/grub/search.h ++++ b/include/grub/search.h +@@ -23,7 +23,8 @@ enum search_flags + { + SEARCH_FLAGS_NONE = 0, + SEARCH_FLAGS_NO_FLOPPY = 1, +- SEARCH_FLAGS_EFIDISK_ONLY = 2 ++ SEARCH_FLAGS_EFIDISK_ONLY = 2, ++ SEARCH_FLAGS_ROOTDEV_ONLY = 4 + }; + + void grub_search_fs_file (const char *key, const char *var, +diff --git a/include/grub/sparc64/linux.h b/include/grub/sparc64/linux.h +new file mode 100644 +index 000000000..e69de29bb +diff --git a/include/grub/types.h b/include/grub/types.h +index 064066e2e..59e030268 100644 +--- a/include/grub/types.h ++++ b/include/grub/types.h +@@ -30,6 +30,7 @@ + #else + #define GRUB_PACKED __attribute__ ((packed)) + #endif ++#define GRUB_ALIGNED(x) __attribute__((aligned (x))) + + #ifdef GRUB_BUILD + # define GRUB_CPU_SIZEOF_VOID_P BUILD_SIZEOF_VOID_P +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 35cf17a8d..59eabb9bb 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -67,6 +67,11 @@ + N_("SBAT metadata"), 0 }, \ + { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \ + N_("disable shim_lock verifier"), 0 }, \ ++ { "x509key", 'x', N_("FILE"), 0, \ ++ N_("embed FILE as an x509 certificate for signature checking"), 0}, \ ++ { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\ ++ "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \ ++ 1}, \ + { "verbose", 'v', 0, 0, \ + N_("print verbose messages."), 1 } + +@@ -129,7 +134,8 @@ enum grub_install_options { + GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS, + GRUB_INSTALL_OPTIONS_DTB, + GRUB_INSTALL_OPTIONS_SBAT, +- GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK ++ GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, ++ GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE + }; + + extern char *grub_install_source_directory; +@@ -185,11 +191,12 @@ void + grub_install_generate_image (const char *dir, const char *prefix, + FILE *out, + const char *outname, char *mods[], +- char *memdisk_path, char **pubkey_paths, +- size_t npubkeys, ++ char *memdisk_path, ++ char **pubkey_paths, size_t npubkeys, ++ char **x509key_paths, size_t nx509keys, + char *config_path, + const struct grub_install_image_target_desc *image_target, +- int note, ++ int note, size_t appsig_size, + grub_compression_t comp, const char *dtb_file, + const char *sbat_path, const int disable_shim_lock); + +diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h +index 3819a6744..6f1da89b9 100644 +--- a/include/grub/util/mkimage.h ++++ b/include/grub/util/mkimage.h +@@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path, + const struct grub_install_image_target_desc *image_target); + void + grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target, +- int note, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char **core_img, size_t *core_size, + Elf32_Addr target_addr, + struct grub_mkimage_layout *layout); + void + grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target, +- int note, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char **core_img, size_t *core_size, + Elf64_Addr target_addr, + struct grub_mkimage_layout *layout); + +diff --git a/include/grub/x86_64/efi/console.h b/include/grub/x86_64/efi/console.h +new file mode 100644 +index 000000000..dba9d8678 +--- /dev/null ++++ b/include/grub/x86_64/efi/console.h +@@ -0,0 +1,24 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_X86_64_EFI_CONSOLE_H ++#define GRUB_X86_64_EFI_CONSOLE_H ++ ++#include ++ ++#endif /* ! GRUB_X86_64_EFI_CONSOLE_H */ +diff --git a/include/grub/x86_64/efi/memory.h b/include/grub/x86_64/efi/memory.h +index 46e9145a3..e81cfb322 100644 +--- a/include/grub/x86_64/efi/memory.h ++++ b/include/grub/x86_64/efi/memory.h +@@ -2,9 +2,11 @@ + #include + + #if defined (__code_model_large__) +-#define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_USABLE_ADDRESS __UINTPTR_MAX__ ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS 0x7fffffff + #else + #define GRUB_EFI_MAX_USABLE_ADDRESS 0x7fffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + #endif + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/po/.gitignore b/po/.gitignore +new file mode 100644 +index 000000000..f507e7741 +--- /dev/null ++++ b/po/.gitignore +@@ -0,0 +1,5 @@ ++/Makefile ++/POTFILES*.in ++/grub.pot ++/remove-potcdate.sed ++/stamp-po +diff --git a/tests/test_asn1.in b/tests/test_asn1.in +new file mode 100644 +index 000000000..8173c5c27 +--- /dev/null ++++ b/tests/test_asn1.in +@@ -0,0 +1,12 @@ ++#! @BUILD_SHEBANG@ ++set -e ++ ++. "@builddir@/grub-core/modinfo.sh" ++ ++out=`echo test_asn1 | @builddir@/grub-shell` ++ ++if [ "$(echo "$out" | tail -n 1)" != "ASN.1 self-tests passed" ]; then ++ echo "ASN.1 test failure: $out" ++ exit 1 ++fi ++ +diff --git a/tests/util/grub-shell-tester.in b/tests/util/grub-shell-tester.in +index 8a87109b1..9a4319d4f 100644 +--- a/tests/util/grub-shell-tester.in ++++ b/tests/util/grub-shell-tester.in +@@ -56,7 +56,7 @@ for option in "$@"; do + usage + exit 0 ;; + -v | --version) +- echo "$0 (GNU GRUB ${PACKAGE_VERSION})" ++ echo "$0 (GRUB ${PACKAGE_VERSION})" + exit 0 ;; + --modules=*) + ms=`echo "$option" | sed -e 's/--modules=//'` +diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in +index 496e1bab3..e0570c88e 100644 +--- a/tests/util/grub-shell.in ++++ b/tests/util/grub-shell.in +@@ -243,7 +243,7 @@ for option in "$@"; do + usage + exit 0 ;; + -v | --version) +- echo "$0 (GNU GRUB ${PACKAGE_VERSION})" ++ echo "$0 (GRUB ${PACKAGE_VERSION})" + exit 0 ;; + --trim) + trim=1 ;; +diff --git a/util/bash-completion.d/.gitignore b/util/bash-completion.d/.gitignore +new file mode 100644 +index 000000000..6813a527a +--- /dev/null ++++ b/util/bash-completion.d/.gitignore +@@ -0,0 +1,2 @@ ++Makefile ++grub +diff --git a/util/bash-completion.d/Makefile.am b/util/bash-completion.d/Makefile.am +index 136287cf1..61108f054 100644 +--- a/util/bash-completion.d/Makefile.am ++++ b/util/bash-completion.d/Makefile.am +@@ -6,7 +6,6 @@ EXTRA_DIST = $(bash_completion_source) + + CLEANFILES = $(bash_completion_script) config.log + +-bashcompletiondir = $(sysconfdir)/bash_completion.d + bashcompletion_DATA = $(bash_completion_script) + + $(bash_completion_script): $(bash_completion_source) $(top_builddir)/config.status +diff --git a/util/bash-completion.d/grub-completion.bash.in b/util/bash-completion.d/grub-completion.bash.in +index 213ce1e57..da7fca5ef 100644 +--- a/util/bash-completion.d/grub-completion.bash.in ++++ b/util/bash-completion.d/grub-completion.bash.in +@@ -275,6 +275,28 @@ have ${__grub_sparc64_setup_program} && \ + unset __grub_sparc64_setup_program + + ++# ++# grub-get-kernel-settings ++# ++_grub_get_kernel_settings () { ++ local cur ++ ++ COMPREPLY=() ++ cur=`_get_cword` ++ ++ if [[ "$cur" == -* ]]; then ++ __grubcomp "$(__grub_get_options_from_help)" ++ else ++ # Default complete with a filename ++ _filedir ++ fi ++} ++__grub_get_kernel_settings_program="@grub_get_kernel_settings@" ++have ${__grub_get_kernel_settings_program} && \ ++ complete -F _grub_get_kernel_settings -o filenames ${__grub_get_kernel_settings_program} ++unset __grub_get_kernel_settings_program ++ ++ + # + # grub-install + # +diff --git a/util/config.c b/util/config.c +index ebcdd8f5e..f044a880a 100644 +--- a/util/config.c ++++ b/util/config.c +@@ -42,6 +42,16 @@ grub_util_parse_config (FILE *f, struct grub_util_config *cfg, int simple) + cfg->is_cryptodisk_enabled = 1; + continue; + } ++ if (grub_strncmp (ptr, "SUSE_BTRFS_SNAPSHOT_BOOTING=", ++ sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1) == 0) ++ { ++ ptr += sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1; ++ if (*ptr == '"' || *ptr == '\'') ++ ptr++; ++ if (grub_strncmp(ptr, "true", sizeof ("true") - 1) == 0) ++ cfg->is_suse_btrfs_snapshot_enabled = 1; ++ continue; ++ } + if (grub_strncmp (ptr, "GRUB_DISTRIBUTOR=", + sizeof ("GRUB_DISTRIBUTOR=") - 1) == 0) + { +diff --git a/util/grub-editenv.c b/util/grub-editenv.c +index db6f187cc..948eec8a1 100644 +--- a/util/grub-editenv.c ++++ b/util/grub-editenv.c +@@ -53,6 +53,9 @@ static struct argp_option options[] = { + /* TRANSLATORS: "unset" is a keyword. It's a summary of "unset" subcommand. */ + {N_("unset [NAME ...]"), 0, 0, OPTION_DOC|OPTION_NO_USAGE, + N_("Delete variables."), 0}, ++ /* TRANSLATORS: "incr" is a keyword. It's a summary of "incr" subcommand. */ ++ {N_("incr [NAME ...]"), 0, 0, OPTION_DOC|OPTION_NO_USAGE, ++ N_("Increase value of integer variables."), 0}, + + {0, 0, 0, OPTION_DOC, N_("Options:"), -1}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, +@@ -253,6 +256,51 @@ unset_variables (const char *name, int argc, char *argv[]) + grub_envblk_close (envblk); + } + ++struct get_int_value_params { ++ char *varname; ++ int value; ++}; ++ ++static int ++get_int_value (const char *varname, const char *value, void *hook_data) ++{ ++ struct get_int_value_params *params = hook_data; ++ ++ if (strcmp (varname, params->varname) == 0) { ++ params->value = strtol (value, NULL, 10); ++ return 1; ++ } ++ return 0; ++} ++ ++static void ++incr_variables (const char *name, int argc, char *argv[]) ++{ ++ grub_envblk_t envblk; ++ char buf[16]; ++ ++ envblk = open_envblk_file (name); ++ while (argc) ++ { ++ struct get_int_value_params params = { ++ .varname = argv[0], ++ .value = 0, /* Consider unset variables 0 */ ++ }; ++ ++ grub_envblk_iterate (envblk, ¶ms, get_int_value); ++ snprintf(buf, sizeof(buf), "%d", params.value + 1); ++ ++ if (! grub_envblk_set (envblk, argv[0], buf)) ++ grub_util_error ("%s", _("environment block too small")); ++ ++ argc--; ++ argv++; ++ } ++ ++ write_envblk (name, envblk); ++ grub_envblk_close (envblk); ++} ++ + int + main (int argc, char *argv[]) + { +@@ -292,6 +340,8 @@ main (int argc, char *argv[]) + set_variables (filename, argc - curindex, argv + curindex); + else if (strcmp (command, "unset") == 0) + unset_variables (filename, argc - curindex, argv + curindex); ++ else if (strcmp (command, "incr") == 0) ++ incr_variables (filename, argc - curindex, argv + curindex); + else + { + char *program = xstrdup(program_name); +diff --git a/util/grub-fstest.c b/util/grub-fstest.c +index 25ae52ab6..982ce9ed7 100644 +--- a/util/grub-fstest.c ++++ b/util/grub-fstest.c +@@ -329,7 +329,7 @@ cmd_cmp (char *src, char *dest) + read_file (src, cmp_hook, ff); + + { +- grub_uint64_t pre; ++ long long pre; + pre = ftell (ff); + fseek (ff, 0, SEEK_END); + if (pre != ftell (ff)) +diff --git a/util/grub-get-kernel-settings.in b/util/grub-get-kernel-settings.in +new file mode 100644 +index 000000000..f71bc6436 +--- /dev/null ++++ b/util/grub-get-kernel-settings.in +@@ -0,0 +1,96 @@ ++#!/bin/sh ++set -e ++ ++# Evaluate new-kernel-pkg's configuration file. ++# Copyright (C) 2016 Free Software Foundation, Inc. ++# ++# GRUB is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# GRUB 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 General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with GRUB. If not, see . ++ ++PACKAGE_NAME=@PACKAGE_NAME@ ++PACKAGE_VERSION=@PACKAGE_VERSION@ ++datadir="@datadir@" ++if [ "x$pkgdatadir" = x ]; then ++ pkgdatadir="${datadir}/@PACKAGE@" ++fi ++ ++self=`basename $0` ++ ++export TEXTDOMAIN=@PACKAGE@ ++export TEXTDOMAINDIR="@localedir@" ++ ++. "${pkgdatadir}/grub-mkconfig_lib" ++ ++# Usage: usage ++# Print the usage. ++usage () { ++ gettext_printf "Usage: %s [OPTION]\n" "$self" ++ gettext "Evaluate new-kernel-pkg configuration"; echo ++ echo ++ print_option_help "-h, --help" "$(gettext "print this message and exit")" ++ print_option_help "-v, --version" "$(gettext "print the version information and exit")" ++ echo ++} ++ ++# Check the arguments. ++while test $# -gt 0 ++do ++ option=$1 ++ shift ++ ++ case "$option" in ++ -h | --help) ++ usage ++ exit 0 ;; ++ -v | --version) ++ echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" ++ exit 0 ;; ++ -*) ++ gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 ++ usage ++ exit 1 ++ ;; ++ # Explicitly ignore non-option arguments, for compatibility. ++ esac ++done ++ ++if test -f /etc/sysconfig/kernel ; then ++ . /etc/sysconfig/kernel ++fi ++ ++GRUB_DEFAULT_KERNEL_TYPE=${DEFAULTKERNEL/-core/} ++if [ "$GRUB_DEFAULT_KERNEL_TYPE" != "kernel" ]; then ++ echo GRUB_NON_STANDARD_KERNEL=true ++ echo export GRUB_NON_STANDARD_KERNEL ++ GRUB_DEFAULT_KERNEL_TYPE=${GRUB_DEFAULT_KERNEL_TYPE/kernel-/} ++fi ++echo GRUB_DEFAULT_KERNEL_TYPE=$GRUB_DEFAULT_KERNEL_TYPE ++echo export GRUB_DEFAULT_KERNEL_TYPE ++if [ "$MAKEDEBUG" = "yes" ]; then ++ echo GRUB_LINUX_MAKE_DEBUG=true ++ echo export GRUB_LINUX_MAKE_DEBUG ++ echo GRUB_CMDLINE_LINUX_DEBUG=\"systemd.log_level=debug systemd.log_target=kmsg\" ++ echo export GRUB_CMDLINE_LINUX_DEBUG ++ echo GRUB_LINUX_DEBUG_TITLE_POSTFIX=\" with debugging\" ++ echo export GRUB_LINUX_DEBUG_TITLE_POSTFIX ++fi ++if [ "$DEFAULTDEBUG" = "yes" ]; then ++ echo GRUB_DEFAULT_TO_DEBUG=true ++else ++ echo GRUB_DEFAULT_TO_DEBUG=false ++fi ++echo export GRUB_DEFAULT_TO_DEBUG ++if [ "$UPDATEDEFAULT" = "yes" ]; then ++ echo GRUB_UPDATE_DEFAULT_KERNEL=true ++ echo export GRUB_UPDATE_DEFAULT_KERNEL ++fi +diff --git a/util/grub-install-common.c b/util/grub-install-common.c +index ce854d86f..67afc2eed 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -368,7 +368,7 @@ char *grub_install_themes_directory = NULL; + int + grub_install_is_short_mbrgap_supported (void) + { +- int i, j; ++ unsigned int i, j; + static const char *whitelist[] = + { + "part_msdos", "biosdisk", "affs", "afs", "bfs", "archelp", +@@ -465,11 +465,15 @@ static char **pubkeys; + static size_t npubkeys; + static char *sbat; + static int disable_shim_lock; ++static char **x509keys; ++static size_t nx509keys; + static grub_compression_t compression; ++static size_t appsig_size; + + int + grub_install_parse (int key, char *arg) + { ++ const char *end; + switch (key) + { + case GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS: +@@ -504,6 +508,12 @@ grub_install_parse (int key, char *arg) + case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK: + disable_shim_lock = 1; + return 1; ++ case 'x': ++ x509keys = xrealloc (x509keys, ++ sizeof (x509keys[0]) ++ * (nx509keys + 1)); ++ x509keys[nx509keys++] = xstrdup (arg); ++ return 1; + + case GRUB_INSTALL_OPTIONS_VERBOSITY: + verbosity++; +@@ -567,6 +577,12 @@ grub_install_parse (int key, char *arg) + grub_util_error (_("Unrecognized compression `%s'"), arg); + case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE: + return 1; ++ case GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE: ++ grub_errno = 0; ++ appsig_size = grub_strtol(arg, &end, 10); ++ if (grub_errno) ++ return 0; ++ return 1; + default: + return 0; + } +@@ -628,6 +644,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + for (pk = pubkeys; pk < pubkeys + npubkeys; pk++) + slen += sizeof (" --pubkey ''") + grub_strlen (*pk); + ++ for (pk = x509keys; pk < x509keys + nx509keys; pk++) ++ slen += 10 + grub_strlen (*pk); ++ + for (md = modules.entries; *md; md++) + slen += sizeof (" ''") + grub_strlen (*md); + +@@ -668,6 +687,14 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + *p++ = '\''; + } + ++ for (pk = x509keys; pk < x509keys + nx509keys; pk++) ++ { ++ p = grub_stpcpy (p, "--x509 '"); ++ p = grub_stpcpy (p, *pk); ++ *p++ = '\''; ++ *p++ = ' '; ++ } ++ + for (md = modules.entries; *md; md++) + { + *p++ = ' '; +@@ -679,9 +706,11 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + *p = '\0'; + + grub_util_info ("grub-mkimage --directory '%s' --prefix '%s' --output '%s'" +- " --format '%s' --compression '%s'%s%s%s\n", ++ " --format '%s' --compression '%s'" ++ " --appended-signture-size %zu %s%s%s\n", + dir, prefix, outname, + mkimage_target, compnames[compression], ++ appsig_size, + note ? " --note" : "", + disable_shim_lock ? " --disable-shim-lock" : "", s); + free (s); +@@ -692,8 +721,10 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + + grub_install_generate_image (dir, prefix, fp, outname, + modules.entries, memdisk_path, +- pubkeys, npubkeys, config_path, tgt, +- note, compression, dtb, sbat, ++ pubkeys, npubkeys, ++ x509keys, nx509keys, ++ config_path, tgt, ++ note, appsig_size, compression, dtb, sbat, + disable_shim_lock); + while (dc--) + grub_install_pop_module (); +diff --git a/util/grub-install.c b/util/grub-install.c +index 7dc5657bb..314b6143b 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -843,6 +843,8 @@ try_open (const char *path) + } + #endif + ++extern int use_relative_path_on_btrfs; ++ + int + main (int argc, char *argv[]) + { +@@ -876,6 +878,9 @@ main (int argc, char *argv[]) + + grub_util_load_config (&config); + ++ if (config.is_suse_btrfs_snapshot_enabled) ++ use_relative_path_on_btrfs = 1; ++ + if (!bootloader_id && config.grub_distributor) + { + char *ptr; +@@ -1026,27 +1031,22 @@ main (int argc, char *argv[]) + + switch (platform) + { +- case GRUB_INSTALL_PLATFORM_I386_EFI: +- case GRUB_INSTALL_PLATFORM_X86_64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: ++ case GRUB_INSTALL_PLATFORM_I386_EFI: ++ case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: +- case GRUB_INSTALL_PLATFORM_IA64_EFI: ++ case GRUB_INSTALL_PLATFORM_X86_64_EFI: + is_efi = 1; ++ if (!force) ++ grub_util_error (_("This utility should not be used for EFI platforms" ++ " because it does not support UEFI Secure Boot." ++ " If you really wish to proceed, invoke the --force" ++ " option.\nMake sure Secure Boot is disabled before" ++ " proceeding")); + break; +- default: +- is_efi = 0; +- break; +- +- /* pacify warning. */ +- case GRUB_INSTALL_PLATFORM_MAX: +- break; +- } +- +- switch (platform) +- { + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + #ifdef __linux__ +@@ -1055,12 +1055,14 @@ main (int argc, char *argv[]) + try_open ("/dev/nvram"); + #endif + break; ++ /* pacify warning. */ ++ case GRUB_INSTALL_PLATFORM_MAX: ++ break; + default: + break; + } + + /* Find the EFI System Partition. */ +- + if (is_efi) + { + grub_fs_t fs; +@@ -1229,18 +1231,8 @@ main (int argc, char *argv[]) + char *d; + + is_guess = 1; +- d = grub_util_path_concat (2, bootdir, "macppc"); +- if (!grub_util_is_directory (d)) +- { +- free (d); +- d = grub_util_path_concat (2, bootdir, "efi"); +- } + /* Find the Mac HFS(+) System Partition. */ +- if (!grub_util_is_directory (d)) +- { +- free (d); +- d = grub_util_path_concat (2, bootdir, "EFI"); +- } ++ d = grub_util_path_concat (2, bootdir, "macppc"); + if (!grub_util_is_directory (d)) + { + free (d); +@@ -1366,6 +1358,15 @@ main (int argc, char *argv[]) + relative_grubdir = xstrdup ("/"); + } + ++ if (config.is_suse_btrfs_snapshot_enabled ++ && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0) ++ { ++ if (!load_cfg_f) ++ load_cfg_f = grub_util_fopen (load_cfg, "wb"); ++ have_load_cfg = 1; ++ fprintf (load_cfg_f, "set btrfs_relative_path='y'\n"); ++ } ++ + char *prefix_drive = NULL; + char *install_drive = NULL; + +@@ -1601,6 +1602,55 @@ main (int argc, char *argv[]) + prefix_drive = xasprintf ("(%s)", grub_drives[0]); + } + ++#ifdef __linux__ ++ ++ if (config.is_suse_btrfs_snapshot_enabled ++ && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0) ++ { ++ char *subvol = NULL; ++ char *mount_path = NULL; ++ char **rootdir_devices = NULL; ++ char *rootdir_path = grub_util_path_concat (2, "/", rootdir); ++ ++ if (grub_util_is_directory (rootdir_path)) ++ rootdir_devices = grub_guess_root_devices (rootdir_path); ++ ++ free (rootdir_path); ++ ++ if (rootdir_devices && rootdir_devices[0]) ++ if (grub_strcmp (rootdir_devices[0], grub_devices[0]) == 0) ++ subvol = grub_util_get_btrfs_subvol (platdir, &mount_path); ++ ++ if (subvol && mount_path) ++ { ++ char *def_subvol; ++ ++ def_subvol = grub_util_get_btrfs_subvol ("/", NULL); ++ ++ if (def_subvol) ++ { ++ if (!load_cfg_f) ++ load_cfg_f = grub_util_fopen (load_cfg, "wb"); ++ have_load_cfg = 1; ++ ++ if (grub_strcmp (subvol, def_subvol) != 0) ++ fprintf (load_cfg_f, "btrfs-mount-subvol ($root) %s %s\n", mount_path, subvol); ++ free (def_subvol); ++ } ++ } ++ ++ for (curdev = rootdir_devices; *curdev; curdev++) ++ free (*curdev); ++ if (rootdir_devices) ++ free (rootdir_devices); ++ if (subvol) ++ free (subvol); ++ if (mount_path) ++ free (mount_path); ++ } ++ ++#endif ++ + char mkimage_target[200]; + const char *core_name = NULL; + +diff --git a/util/grub-menulst2cfg.c b/util/grub-menulst2cfg.c +index b80e15cc3..1ea2a86e1 100644 +--- a/util/grub-menulst2cfg.c ++++ b/util/grub-menulst2cfg.c +@@ -34,7 +34,7 @@ main (int argc, char **argv) + char *buf = NULL; + size_t bufsize = 0; + char *suffix = xstrdup (""); +- int suffixlen = 0; ++ size_t suffixlen = 0; + const char *out_fname = 0; + + grub_util_host_init (&argc, &argv); +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index 32c480dae..1cfb5873f 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -45,10 +45,13 @@ grub_probe="${sbindir}/@grub_probe@" + grub_file="${bindir}/@grub_file@" + grub_editenv="${bindir}/@grub_editenv@" + grub_script_check="${bindir}/@grub_script_check@" ++grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@" + + export TEXTDOMAIN=@PACKAGE@ + export TEXTDOMAINDIR="@localedir@" + ++export GRUB_GRUBENV_UPDATE="yes" ++ + . "${pkgdatadir}/grub-mkconfig_lib" + + # Usage: usage +@@ -58,6 +61,7 @@ usage () { + gettext "Generate a grub config file"; echo + echo + print_option_help "-o, --output=$(gettext FILE)" "$(gettext "output generated config to FILE [default=stdout]")" ++ print_option_help "--no-grubenv-update" "$(gettext "do not update variables in the grubenv file")" + print_option_help "-h, --help" "$(gettext "print this message and exit")" + print_option_help "-V, --version" "$(gettext "print the version information and exit")" + echo +@@ -93,6 +97,9 @@ do + --output=*) + grub_cfg=`echo "$option" | sed 's/--output=//'` + ;; ++ --no-grubenv-update) ++ GRUB_GRUBENV_UPDATE="no" ++ ;; + -*) + gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 + usage +@@ -102,6 +109,14 @@ do + esac + done + ++os_name=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g') ++if test -s "${grub_cfg}" && test "x${grub_cfg}" = "x/boot/efi/EFI/$os_name/grub.cfg"; then ++ gettext_printf "Running \`grub2-mkconfig -o %s' will overwrite the GRUB wrapper.\n" "$grub_cfg" 1>&2 ++ gettext_printf "Please run \`grub2-mkconfig -o /boot/grub2/grub.cfg' instead to update grub.cfg.\n" 1>&2 ++ gettext_printf "GRUB configuration file was not updated.\n" 1>&2 ++ exit 1 ++fi ++ + if [ "x$EUID" = "x" ] ; then + EUID=`id -u` + fi +@@ -140,9 +155,6 @@ GRUB_DEVICE_PARTUUID="`${grub_probe} --device ${GRUB_DEVICE} --target=partuuid 2 + GRUB_DEVICE_BOOT="`${grub_probe} --target=device /boot`" + GRUB_DEVICE_BOOT_UUID="`${grub_probe} --device ${GRUB_DEVICE_BOOT} --target=fs_uuid 2> /dev/null`" || true + +-# Disable os-prober by default due to security reasons. +-GRUB_DISABLE_OS_PROBER="true" +- + # Filesystem for the device containing our userland. Used for stuff like + # choosing Hurd filesystem module. + GRUB_FS="`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2> /dev/null || echo unknown`" +@@ -161,6 +173,8 @@ if test -f ${sysconfdir}/default/grub ; then + . ${sysconfdir}/default/grub + fi + ++eval "$("${grub_get_kernel_settings}")" || true ++ + if [ "x${GRUB_DISABLE_UUID}" = "xtrue" ]; then + if [ -z "${GRUB_DISABLE_LINUX_UUID}" ]; then + GRUB_DISABLE_LINUX_UUID="true" +@@ -204,7 +218,6 @@ export GRUB_DEVICE \ + GRUB_DEVICE_PARTUUID \ + GRUB_DEVICE_BOOT \ + GRUB_DEVICE_BOOT_UUID \ +- GRUB_DISABLE_OS_PROBER \ + GRUB_FS \ + GRUB_FONT \ + GRUB_PRELOAD_MODULES \ +@@ -250,12 +263,16 @@ export GRUB_DEFAULT \ + GRUB_BACKGROUND \ + GRUB_THEME \ + GRUB_GFXPAYLOAD_LINUX \ ++ GRUB_DISABLE_OS_PROBER \ + GRUB_INIT_TUNE \ + GRUB_SAVEDEFAULT \ + GRUB_ENABLE_CRYPTODISK \ + GRUB_BADRAM \ + GRUB_OS_PROBER_SKIP_LIST \ +- GRUB_DISABLE_SUBMENU ++ GRUB_DISABLE_SUBMENU \ ++ GRUB_DEFAULT_DTB \ ++ SUSE_BTRFS_SNAPSHOT_BOOTING \ ++ GRUB_ENABLE_BLSCFG + + if test "x${grub_cfg}" != "x"; then + rm -f "${grub_cfg}.new" +@@ -282,6 +299,8 @@ for i in "${grub_mkconfig_dir}"/* ; do + *~) ;; + # emacsen autosave files. FIXME: support other editors + */\#*\#) ;; ++ # rpm config files of yore. ++ *.rpmsave|*.rpmnew|*.rpmorig) ;; + *) + if grub_file_is_not_garbage "$i" && test -x "$i" ; then + echo +@@ -305,7 +324,7 @@ and /etc/grub.d/* files or please file a bug report with + else + # none of the children aborted with error, install the new grub.cfg + oldumask=$(umask) +- umask 077 ++ umask 177 + cat ${grub_cfg}.new > ${grub_cfg} + umask $oldumask + rm -f ${grub_cfg}.new +diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in +index 33e1750ae..4eadcba4b 100644 +--- a/util/grub-mkconfig_lib.in ++++ b/util/grub-mkconfig_lib.in +@@ -30,6 +30,9 @@ fi + if test "x$grub_file" = x; then + grub_file="${bindir}/@grub_file@" + fi ++if test "x$grub_editenv" = x; then ++ grub_editenv="${bindir}/@grub_editenv@" ++fi + if test "x$grub_mkrelpath" = x; then + grub_mkrelpath="${bindir}/@grub_mkrelpath@" + fi +@@ -49,7 +52,11 @@ grub_warn () + + make_system_path_relative_to_its_root () + { ++ if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] ; then ++ "${grub_mkrelpath}" -r "$1" ++ else + "${grub_mkrelpath}" "$1" ++ fi + } + + is_path_readable_by_grub () +@@ -118,8 +125,19 @@ EOF + fi + } + ++prepare_grub_to_access_device_with_variable () ++{ ++ device_variable="$1" ++ shift ++ prepare_grub_to_access_device "$@" ++ unset "device_variable" ++} ++ + prepare_grub_to_access_device () + { ++ if [ -z "$device_variable" ]; then ++ device_variable="root" ++ fi + old_ifs="$IFS" + IFS=' + ' +@@ -154,18 +172,18 @@ prepare_grub_to_access_device () + # otherwise set root as per value in device.map. + fs_hint="`"${grub_probe}" --device $@ --target=compatibility_hint`" + if [ "x$fs_hint" != x ]; then +- echo "set root='$fs_hint'" ++ echo "set ${device_variable}='$fs_hint'" + fi + if [ "x${GRUB_DISABLE_UUID}" != "xtrue" ] && fs_uuid="`"${grub_probe}" --device $@ --target=fs_uuid 2> /dev/null`" ; then + hints="`"${grub_probe}" --device $@ --target=hints_string 2> /dev/null`" || hints= + if [ "x$hints" != x ]; then + echo "if [ x\$feature_platform_search_hint = xy ]; then" +- echo " search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}" ++ echo " search --no-floppy --fs-uuid --set=${device_variable} ${hints} ${fs_uuid}" + echo "else" +- echo " search --no-floppy --fs-uuid --set=root ${fs_uuid}" ++ echo " search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}" + echo "fi" + else +- echo "search --no-floppy --fs-uuid --set=root ${fs_uuid}" ++ echo "search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}" + fi + fi + IFS="$old_ifs" +@@ -281,6 +299,14 @@ version_test_gt () + *.old:*.old) ;; + *.old:*) version_test_gt_a="`echo "$version_test_gt_a" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=gt ;; + *:*.old) version_test_gt_b="`echo "$version_test_gt_b" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=ge ;; ++ *-rescue*:*-rescue*) ;; ++ *?debug:*?debug) ;; ++ *-rescue*:*?debug) return 1 ;; ++ *?debug:*-rescue*) return 0 ;; ++ *-rescue*:*) return 1 ;; ++ *:*-rescue*) return 0 ;; ++ *?debug:*) return 1 ;; ++ *:*?debug) return 0 ;; + esac + version_test_numeric "$version_test_gt_a" "$version_test_gt_cmp" "$version_test_gt_b" + return "$?" +diff --git a/util/grub-mkfont.c b/util/grub-mkfont.c +index 7624d7808..e8a914021 100644 +--- a/util/grub-mkfont.c ++++ b/util/grub-mkfont.c +@@ -143,7 +143,8 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + int width, height; + int cuttop, cutbottom, cutleft, cutright; + grub_uint8_t *data; +- int mask, i, j, bitmap_size; ++ int mask, i, bitmap_size; ++ unsigned int j; + FT_GlyphSlot glyph; + int flag = FT_LOAD_RENDER | FT_LOAD_MONOCHROME; + FT_Error err; +@@ -188,7 +189,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + cuttop = cutbottom = cutleft = cutright = 0; + else + { +- for (cuttop = 0; cuttop < glyph->bitmap.rows; cuttop++) ++ for (cuttop = 0; cuttop < (long)glyph->bitmap.rows; cuttop++) + { + for (j = 0; j < glyph->bitmap.width; j++) + if (glyph->bitmap.buffer[j / 8 + cuttop * glyph->bitmap.pitch] +@@ -208,10 +209,10 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + break; + } + cutbottom = glyph->bitmap.rows - 1 - cutbottom; +- if (cutbottom + cuttop >= glyph->bitmap.rows) ++ if (cutbottom + cuttop >= (long)glyph->bitmap.rows) + cutbottom = 0; + +- for (cutleft = 0; cutleft < glyph->bitmap.width; cutleft++) ++ for (cutleft = 0; cutleft < (long)glyph->bitmap.width; cutleft++) + { + for (j = 0; j < glyph->bitmap.rows; j++) + if (glyph->bitmap.buffer[cutleft / 8 + j * glyph->bitmap.pitch] +@@ -230,7 +231,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + break; + } + cutright = glyph->bitmap.width - 1 - cutright; +- if (cutright + cutleft >= glyph->bitmap.width) ++ if (cutright + cutleft >= (long)glyph->bitmap.width) + cutright = 0; + } + +@@ -267,7 +268,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + + mask = 0; + data = &glyph_info->bitmap[0] - 1; +- for (j = cuttop; j < height + cuttop; j++) ++ for (j = cuttop; j < (long)height + cuttop; j++) + for (i = cutleft; i < width + cutleft; i++) + add_pixel (&data, &mask, + glyph->bitmap.buffer[i / 8 + j * glyph->bitmap.pitch] & +diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c +index c0d559937..e1f111278 100644 +--- a/util/grub-mkimage.c ++++ b/util/grub-mkimage.c +@@ -75,7 +75,8 @@ static struct argp_option options[] = { + /* TRANSLATORS: "embed" is a verb (command description). "*/ + {"config", 'c', N_("FILE"), 0, N_("embed FILE as an early config"), 0}, + /* TRANSLATORS: "embed" is a verb (command description). "*/ +- {"pubkey", 'k', N_("FILE"), 0, N_("embed FILE as public key for signature checking"), 0}, ++ {"pubkey", 'k', N_("FILE"), 0, N_("embed FILE as public key for PGP signature checking"), 0}, ++ {"x509", 'x', N_("FILE"), 0, N_("embed FILE as an x509 certificate for appended signature checking"), 0}, + /* TRANSLATORS: NOTE is a name of segment. */ + {"note", 'n', 0, 0, N_("add NOTE segment for CHRP IEEE1275"), 0}, + {"output", 'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0}, +@@ -84,6 +85,7 @@ static struct argp_option options[] = { + {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0}, + {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, ++ {"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0}, + { 0, 0, 0, 0, 0, 0 } + }; + +@@ -123,11 +125,14 @@ struct arguments + char *dtb; + char **pubkeys; + size_t npubkeys; ++ char **x509keys; ++ size_t nx509keys; + char *font; + char *config; + char *sbat; + int note; + int disable_shim_lock; ++ size_t appsig_size; + const struct grub_install_image_target_desc *image_target; + grub_compression_t comp; + }; +@@ -138,6 +143,7 @@ argp_parser (int key, char *arg, struct argp_state *state) + /* Get the input argument from argp_parse, which we + know is a pointer to our arguments structure. */ + struct arguments *arguments = state->input; ++ const char* end; + + switch (key) + { +@@ -170,6 +176,13 @@ argp_parser (int key, char *arg, struct argp_state *state) + arguments->note = 1; + break; + ++ case 'S': ++ grub_errno = 0; ++ arguments->appsig_size = grub_strtol(arg, &end, 10); ++ if (grub_errno) ++ return 0; ++ break; ++ + case 'm': + if (arguments->memdisk) + free (arguments->memdisk); +@@ -196,6 +209,13 @@ argp_parser (int key, char *arg, struct argp_state *state) + arguments->pubkeys[arguments->npubkeys++] = xstrdup (arg); + break; + ++ case 'x': ++ arguments->x509keys = xrealloc (arguments->x509keys, ++ sizeof (arguments->x509keys[0]) ++ * (arguments->nx509keys + 1)); ++ arguments->x509keys[arguments->nx509keys++] = xstrdup (arg); ++ break; ++ + case 'c': + if (arguments->config) + free (arguments->config); +@@ -322,10 +342,12 @@ main (int argc, char *argv[]) + grub_install_generate_image (arguments.dir, arguments.prefix, fp, + arguments.output, arguments.modules, + arguments.memdisk, arguments.pubkeys, +- arguments.npubkeys, arguments.config, ++ arguments.npubkeys, arguments.x509keys, ++ arguments.nx509keys, arguments.config, + arguments.image_target, arguments.note, +- arguments.comp, arguments.dtb, +- arguments.sbat, arguments.disable_shim_lock); ++ arguments.appsig_size, arguments.comp, ++ arguments.dtb, arguments.sbat, ++ arguments.disable_shim_lock); + + if (grub_util_file_sync (fp) < 0) + grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout", +diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c +index e50b29533..9488f0525 100644 +--- a/util/grub-mkimagexx.c ++++ b/util/grub-mkimagexx.c +@@ -85,6 +85,15 @@ struct grub_ieee1275_note + struct grub_ieee1275_note_desc descriptor; + }; + ++#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature" ++#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */ ++ ++struct grub_appended_signature_note ++{ ++ Elf32_Nhdr header; ++ char name[ALIGN_UP(sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 4)]; ++}; ++ + #define GRUB_XEN_NOTE_NAME "Xen" + + struct fixup_block_list +@@ -208,7 +217,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr) + + void + SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target, +- int note, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char **core_img, size_t *core_size, + Elf_Addr target_addr, + struct grub_mkimage_layout *layout) + { +@@ -222,6 +231,12 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + int shnum = 4; + int string_size = sizeof (".text") + sizeof ("mods") + 1; + ++ if (appsig_size) ++ { ++ phnum++; ++ footer_size += ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4); ++ } ++ + if (image_target->id != IMAGE_LOONGSON_ELF) + phnum += 2; + +@@ -485,6 +500,28 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + phdr->p_offset = grub_host_to_target32 (header_size + program_size); + } + ++ if (appsig_size) { ++ int note_size = ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4); ++ struct grub_appended_signature_note *note_ptr = (struct grub_appended_signature_note *) ++ (elf_img + program_size + header_size + (note ? sizeof (struct grub_ieee1275_note) : 0)); ++ ++ note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME)); ++ /* needs to sit at the end, so we round this up and sign some zero padding */ ++ note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP(appsig_size, 4)); ++ note_ptr->header.n_type = grub_host_to_target32 (GRUB_APPENDED_SIGNATURE_NOTE_TYPE); ++ strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME); ++ ++ phdr++; ++ phdr->p_type = grub_host_to_target32 (PT_NOTE); ++ phdr->p_flags = grub_host_to_target32 (PF_R); ++ phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof); ++ phdr->p_vaddr = 0; ++ phdr->p_paddr = 0; ++ phdr->p_filesz = grub_host_to_target32 (note_size); ++ phdr->p_memsz = 0; ++ phdr->p_offset = grub_host_to_target32 (header_size + program_size + (note ? sizeof (struct grub_ieee1275_note) : 0)); ++ } ++ + { + char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr) + + shnum * sizeof (*shdr)); +diff --git a/util/grub-mknetdir.c b/util/grub-mknetdir.c +index 46f304c2b..11c9db117 100644 +--- a/util/grub-mknetdir.c ++++ b/util/grub-mknetdir.c +@@ -32,13 +32,15 @@ + + static char *rootdir = NULL, *subdir = NULL; + static char *debug_image = NULL; ++static char efi_netfs = 0; + + enum + { + OPTION_NET_DIRECTORY = 0x301, + OPTION_SUBDIR, + OPTION_DEBUG, +- OPTION_DEBUG_IMAGE ++ OPTION_DEBUG_IMAGE, ++ OPTION_DEBUG_EFI_NETFS + }; + + static struct argp_option options[] = { +@@ -49,6 +51,7 @@ static struct argp_option options[] = { + 0, N_("relative subdirectory on network server"), 2}, + {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2}, + {"debug-image", OPTION_DEBUG_IMAGE, N_("STRING"), OPTION_HIDDEN, 0, 2}, ++ {"debug-efi-netfs", OPTION_DEBUG_EFI_NETFS, 0, OPTION_HIDDEN, 0, 2}, + {0, 0, 0, 0, 0, 0} + }; + +@@ -67,6 +70,9 @@ argp_parser (int key, char *arg, struct argp_state *state) + free (subdir); + subdir = xstrdup (arg); + return 0; ++ case OPTION_DEBUG_EFI_NETFS: ++ efi_netfs = 1; ++ return 0; + /* This is an undocumented feature... */ + case OPTION_DEBUG: + verbosity++; +@@ -82,7 +88,6 @@ argp_parser (int key, char *arg, struct argp_state *state) + } + } + +- + struct argp argp = { + options, argp_parser, NULL, + "\v"N_("Prepares GRUB network boot images at net_directory/subdir " +@@ -92,7 +97,7 @@ struct argp argp = { + + static char *base; + +-static const struct ++static struct + { + const char *mkimage_target; + const char *netmodule; +@@ -157,6 +162,7 @@ process_input_dir (const char *input_dir, enum grub_install_plat platform) + grub_install_push_module (targets[platform].netmodule); + + output = grub_util_path_concat_ext (2, grubdir, "core", targets[platform].ext); ++ + grub_install_make_image_wrap (input_dir, prefix, output, + 0, load_cfg, + targets[platform].mkimage_target, 0); +@@ -196,7 +202,16 @@ main (int argc, char *argv[]) + + grub_install_mkdir_p (base); + +- grub_install_push_module ("tftp"); ++ if (!efi_netfs) ++ { ++ grub_install_push_module ("tftp"); ++ grub_install_push_module ("http"); ++ } ++ else ++ { ++ targets[GRUB_INSTALL_PLATFORM_I386_EFI].netmodule = "efi_netfs"; ++ targets[GRUB_INSTALL_PLATFORM_X86_64_EFI].netmodule = "efi_netfs"; ++ } + + if (!grub_install_source_directory) + { +diff --git a/util/grub-mkrelpath.c b/util/grub-mkrelpath.c +index 47a241a39..5db7a9a7d 100644 +--- a/util/grub-mkrelpath.c ++++ b/util/grub-mkrelpath.c +@@ -40,9 +40,12 @@ struct arguments + }; + + static struct argp_option options[] = { ++ {"relative", 'r', 0, 0, "use relative path on btrfs", 0}, + { 0, 0, 0, 0, 0, 0 } + }; + ++extern int use_relative_path_on_btrfs; ++ + static error_t + argp_parser (int key, char *arg, struct argp_state *state) + { +@@ -52,6 +55,9 @@ argp_parser (int key, char *arg, struct argp_state *state) + + switch (key) + { ++ case 'r': ++ use_relative_path_on_btrfs = 1; ++ break; + case ARGP_KEY_ARG: + if (state->arg_num == 0) + arguments->pathname = xstrdup (arg); +diff --git a/util/grub-mount.c b/util/grub-mount.c +index bf4c8b891..d369e2166 100644 +--- a/util/grub-mount.c ++++ b/util/grub-mount.c +@@ -269,11 +269,17 @@ fuse_read (const char *path, char *buf, size_t sz, off_t off, + { + grub_file_t file = files[fi->fh]; + grub_ssize_t size; ++ grub_off_t offset; + +- if (off > file->size) ++ if (off < 0) + return -EINVAL; + +- file->offset = off; ++ if ((grub_off_t)off > file->size) ++ return -EINVAL; ++ ++ offset = (grub_off_t)off; ++ ++ file->offset = offset; + + size = grub_file_read (file, buf, sz); + if (size < 0) +diff --git a/util/grub-probe.c b/util/grub-probe.c +index 65c1ca3f8..08ae915e8 100644 +--- a/util/grub-probe.c ++++ b/util/grub-probe.c +@@ -799,7 +799,7 @@ argp_parser (int key, char *arg, struct argp_state *state) + + case 't': + { +- int i; ++ unsigned int i; + + for (i = PRINT_FS; i < ARRAY_SIZE (targets); i++) + if (strcmp (arg, targets[i]) == 0) +diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c +new file mode 100644 +index 000000000..31a868aec +--- /dev/null ++++ b/util/grub-set-bootflag.c +@@ -0,0 +1,319 @@ ++/* grub-set-bootflag.c - tool to set boot-flags in the grubenv. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2018 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++/* ++ * NOTE this gets run by users as root (its suid root), so this does not ++ * use any grub library / util functions to allow for easy auditing. ++ * The grub headers are only included to get certain defines. ++ */ ++ ++#include /* For *_DIR_NAME defines */ ++#include ++#include ++#include /* For GRUB_ENVBLK_DEFCFG define */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "progname.h" ++ ++#define GRUBENV "/" GRUB_BOOT_DIR_NAME "/" GRUB_DIR_NAME "/" GRUB_ENVBLK_DEFCFG ++#define GRUBENV_SIZE 1024 ++ ++const char *bootflags[] = { ++ "boot_success", ++ "menu_show_once", ++ NULL ++}; ++ ++static void usage(FILE *out) ++{ ++ int i; ++ ++ fprintf (out, "Usage: 'grub-set-bootflag ', where is one of:\n"); ++ for (i = 0; bootflags[i]; i++) ++ fprintf (out, " %s\n", bootflags[i]); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ /* NOTE buf must be at least the longest bootflag length + 4 bytes */ ++ char env[GRUBENV_SIZE + 1 + 2], buf[64], *s; ++ /* +1 for 0 termination, +11 for ".%u" in tmp filename */ ++ char env_filename[PATH_MAX + 1], tmp_filename[PATH_MAX + 11 + 1]; ++ const char *bootflag; ++ int i, fd, len, ret; ++ FILE *f; ++ ++ umask(077); ++ ++ if (argc != 2) ++ { ++ usage (stderr); ++ return 1; ++ } ++ else if (!strcmp (argv[1], "--help")) ++ { ++ usage (stdout); ++ return 0; ++ } ++ else if (!strcmp (argv[1], "--version")) ++ { ++ printf ("grub-set-bootflag (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); ++ return 0; ++ } ++ ++ for (i = 0; bootflags[i]; i++) ++ if (!strcmp (argv[1], bootflags[i])) ++ break; ++ if (!bootflags[i]) ++ { ++ fprintf (stderr, "Invalid bootflag: '%s'\n", argv[1]); ++ usage (stderr); ++ return 1; ++ } ++ ++ bootflag = bootflags[i]; ++ len = strlen (bootflag); ++ ++ /* ++ * Exit calmly when not installed SUID root and invoked by non-root. This ++ * allows installing user/grub-boot-success.service unconditionally while ++ * supporting non-SUID installation of the program for some limited usage. ++ */ ++ if (geteuid()) ++ { ++ printf ("grub-set-bootflag not running as root, no action taken\n"); ++ return 0; ++ } ++ ++ /* ++ * setegid avoids the new grubenv's gid being that of the user. ++ */ ++ if (setegid(0)) ++ { ++ perror ("setegid(0) failed"); ++ return 1; ++ } ++ ++ /* Canonicalize GRUBENV filename, resolving symlinks, etc. */ ++ if (!realpath(GRUBENV, env_filename)) ++ { ++ perror ("Error canonicalizing " GRUBENV " filename"); ++ return 1; ++ } ++ ++ f = fopen (env_filename, "r"); ++ if (!f) ++ { ++ perror ("Error opening " GRUBENV " for reading"); ++ return 1; ++ } ++ ++ ret = fread (env, 1, GRUBENV_SIZE, f); ++ fclose (f); ++ if (ret != GRUBENV_SIZE) ++ { ++ errno = EINVAL; ++ perror ("Error reading from " GRUBENV); ++ return 1; ++ } ++ ++ /* 0 terminate env */ ++ env[GRUBENV_SIZE] = 0; ++ /* not a valid flag value */ ++ env[GRUBENV_SIZE + 1] = 0; ++ env[GRUBENV_SIZE + 2] = 0; ++ ++ if (strncmp (env, GRUB_ENVBLK_SIGNATURE, strlen (GRUB_ENVBLK_SIGNATURE))) ++ { ++ fprintf (stderr, "Error invalid environment block\n"); ++ return 1; ++ } ++ ++ /* Find a pre-existing definition of the bootflag */ ++ s = strstr (env, bootflag); ++ while (s && s[len] != '=') ++ s = strstr (s + len, bootflag); ++ ++ if (s && ((s[len + 1] != '0' && s[len + 1] != '1') || s[len + 2] != '\n')) ++ { ++ fprintf (stderr, "Pre-existing bootflag '%s' has unexpected value\n", bootflag); ++ return 1; ++ } ++ ++ /* No pre-existing bootflag? -> find free space */ ++ if (!s) ++ { ++ for (i = 0; i < (len + 3); i++) ++ buf[i] = '#'; ++ buf[i] = 0; ++ s = strstr (env, buf); ++ } ++ ++ if (!s) ++ { ++ fprintf (stderr, "No space in grubenv to store bootflag '%s'\n", bootflag); ++ return 1; ++ } ++ ++ /* The grubenv is not 0 terminated, so memcpy the name + '=' , '1', '\n' */ ++ snprintf(buf, sizeof(buf), "%s=1\n", bootflag); ++ if (!memcmp(s, buf, len + 3)) ++ return 0; /* nothing to do */ ++ memcpy(s, buf, len + 3); ++ ++ struct rlimit rlim; ++ if (getrlimit(RLIMIT_FSIZE, &rlim) || rlim.rlim_cur < GRUBENV_SIZE || rlim.rlim_max < GRUBENV_SIZE) ++ { ++ fprintf (stderr, "Resource limits undetermined or too low\n"); ++ return 1; ++ } ++ ++ /* ++ * Here we work under the premise that we shouldn't write into the target ++ * file directly because we might not be able to have all of our changes ++ * written completely and atomically. That was CVE-2019-14865, known to ++ * have been triggerable via RLIMIT_FSIZE. While we've dealt with that ++ * specific attack via the check above, there may be other possibilities. ++ */ ++ ++ /* ++ * Create a tempfile for writing the new env. Use the canonicalized filename ++ * for the template so that the tmpfile is in the same dir / on same fs. ++ * ++ * We now use per-user fixed temporary filenames, so that a user cannot cause ++ * multiple files to accumulate. ++ * ++ * We don't use O_EXCL so that a stale temporary file doesn't prevent further ++ * usage of the program by the user. ++ */ ++ snprintf(tmp_filename, sizeof(tmp_filename), "%s.%u", env_filename, getuid()); ++ fd = open(tmp_filename, O_CREAT | O_WRONLY, 0600); ++ if (fd == -1) ++ { ++ perror ("Creating tmpfile failed"); ++ return 1; ++ } ++ ++ /* ++ * The lock prevents the same user from reaching further steps ending in ++ * rename() concurrently, in which case the temporary file only partially ++ * written by one invocation could be renamed to the target file by another. ++ * ++ * The lock also guards the slow fsync() from concurrent calls. After the ++ * first time that and the rename() complete, further invocations for the ++ * same flag become no-ops. ++ * ++ * We lock the temporary file rather than the target file because locking the ++ * latter would allow any user having SIGSTOP'ed their process to make all ++ * other users' invocations fail (or lock up if we'd use blocking mode). ++ * ++ * We use non-blocking mode (LOCK_NB) because the lock having been taken by ++ * another process implies that the other process would normally have already ++ * renamed the file to target by the time it releases the lock (and we could ++ * acquire it), so we'd be working directly on the target if we proceeded, ++ * which is undesirable, and we'd kind of fail on the already-done rename. ++ */ ++ if (flock(fd, LOCK_EX | LOCK_NB)) ++ { ++ perror ("Locking tmpfile failed"); ++ return 1; ++ } ++ ++ /* ++ * Deal with the potential that another invocation proceeded all the way to ++ * rename() and process exit while we were between open() and flock(). ++ */ ++ { ++ struct stat st1, st2; ++ if (fstat(fd, &st1) || stat(tmp_filename, &st2)) ++ { ++ perror ("stat of tmpfile failed"); ++ return 1; ++ } ++ if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) ++ { ++ fprintf (stderr, "Another invocation won race\n"); ++ return 1; ++ } ++ } ++ ++ f = fdopen (fd, "w"); ++ if (!f) ++ { ++ perror ("Error fdopen of tmpfile failed"); ++ unlink(tmp_filename); ++ return 1; ++ } ++ ++ ret = fwrite (env, 1, GRUBENV_SIZE, f); ++ if (ret != GRUBENV_SIZE) ++ { ++ perror ("Error writing tmpfile"); ++ unlink(tmp_filename); ++ return 1; ++ } ++ ++ ret = fflush (f); ++ if (ret) ++ { ++ perror ("Error flushing tmpfile"); ++ unlink(tmp_filename); ++ return 1; ++ } ++ ++ ret = ftruncate (fileno (f), GRUBENV_SIZE); ++ if (ret) ++ { ++ perror ("Error truncating tmpfile"); ++ unlink(tmp_filename); ++ return 1; ++ } ++ ++ ret = fsync (fileno (f)); ++ if (ret) ++ { ++ perror ("Error syncing tmpfile"); ++ unlink(tmp_filename); ++ return 1; ++ } ++ ++ /* ++ * We must not close the file before rename() as that would remove the lock. ++ * ++ * And finally rename the tmpfile with the new env over the old env, the ++ * linux kernel guarantees that this is atomic (from a syscall pov). ++ */ ++ ret = rename(tmp_filename, env_filename); ++ if (ret) ++ { ++ perror ("Error renaming tmpfile to " GRUBENV " failed"); ++ unlink(tmp_filename); ++ return 1; ++ } ++ ++ return 0; ++} +diff --git a/util/grub-set-password.in b/util/grub-set-password.in +new file mode 100644 +index 000000000..d8005e5a1 +--- /dev/null ++++ b/util/grub-set-password.in +@@ -0,0 +1,121 @@ ++#!/bin/sh -e ++ ++grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` ++ ++PACKAGE_VERSION="@PACKAGE_VERSION@" ++PACKAGE_NAME="@PACKAGE_NAME@" ++self=`basename $0` ++bindir="@bindir@" ++grub_mkpasswd="${bindir}/@grub_mkpasswd_pbkdf2@" ++ ++# Usage: usage ++# Print the usage. ++usage () { ++ cat < put user.cfg in a user-selected directory ++ ++Report bugs at https://bugzilla.redhat.com. ++EOF ++} ++ ++argument () { ++ opt=$1 ++ shift ++ ++ if test $# -eq 0; then ++ gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$opt" 1>&2 ++ exit 1 ++ fi ++ echo $1 ++} ++ ++# Ensure that it's the root user running this script ++if [ "${EUID}" -ne 0 ]; then ++ echo "The grub bootloader password may only be set by root." ++ usage ++ exit 2 ++fi ++ ++# Check the arguments. ++while test $# -gt 0 ++do ++ option=$1 ++ shift ++ ++ case "$option" in ++ -h | --help) ++ usage ++ exit 0 ;; ++ -v | --version) ++ echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" ++ exit 0 ;; ++ -o | --output) ++ OUTPUT_PATH=`argument $option "$@"`; shift ;; ++ --output=*) ++ OUTPUT_PATH=`echo "$option" | sed 's/--output=//'` ;; ++ -o=*) ++ OUTPUT_PATH=`echo "$option" | sed 's/-o=//'` ;; ++ esac ++done ++ ++# set user input or default path for user.cfg file ++if [ -z "${OUTPUT_PATH}" ]; then ++ OUTPUT_PATH="${grubdir}" ++fi ++ ++if [ ! -d "${OUTPUT_PATH}" ]; then ++ echo "${OUTPUT_PATH} does not exist." ++ usage ++ exit 2; ++fi ++ ++ttyopt=$(stty -g) ++fixtty() { ++ stty ${ttyopt} ++} ++ ++trap fixtty EXIT ++stty -echo ++ ++# prompt & confirm new grub2 root user password ++echo -n "Enter password: " ++read PASSWORD ++echo ++echo -n "Confirm password: " ++read PASSWORD_CONFIRM ++echo ++stty ${ttyopt} ++ ++getpass() { ++ local P0 ++ local P1 ++ P0="$1" && shift ++ P1="$1" && shift ++ ++ ( echo ${P0} ; echo ${P1} ) | \ ++ LC_ALL=C ${grub_mkpasswd} | \ ++ grep -v '[eE]nter password:' | \ ++ sed -e "s/PBKDF2 hash of your password is //" ++} ++ ++MYPASS="$(getpass "${PASSWORD}" "${PASSWORD_CONFIRM}")" ++if [ -z "${MYPASS}" ]; then ++ echo "${self}: error: empty password" 1>&2 ++ exit 1 ++fi ++ ++install -m 0600 /dev/null "${OUTPUT_PATH}/user.cfg" 2>/dev/null || : ++chmod 0600 "${OUTPUT_PATH}/user.cfg" 2>/dev/null || : ++echo "GRUB2_PASSWORD=${MYPASS}" > "${OUTPUT_PATH}/user.cfg" ++ ++if ! grep -q "^### BEGIN /etc/grub.d/01_users ###$" "${OUTPUT_PATH}/grub.cfg"; then ++ echo "WARNING: The current configuration lacks password support!" ++ echo "Update your configuration with @grub_mkconfig@ to support this feature." ++fi +diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in +new file mode 100644 +index 000000000..a851424be +--- /dev/null ++++ b/util/grub-switch-to-blscfg.in +@@ -0,0 +1,317 @@ ++#! /bin/sh ++# ++# Set a default boot entry for GRUB. ++# Copyright (C) 2004,2009 Free Software Foundation, Inc. ++# ++# GRUB is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# GRUB 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 General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with GRUB. If not, see . ++ ++#set -eu ++ ++# Initialize some variables. ++prefix=@prefix@ ++exec_prefix=@exec_prefix@ ++sbindir=@sbindir@ ++bindir=@bindir@ ++sysconfdir="@sysconfdir@" ++PACKAGE_NAME=@PACKAGE_NAME@ ++PACKAGE_VERSION=@PACKAGE_VERSION@ ++datarootdir="@datarootdir@" ++datadir="@datadir@" ++if [ ! -v pkgdatadir ]; then ++ pkgdatadir="${datadir}/@PACKAGE@" ++fi ++ ++self=`basename $0` ++ ++grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@" ++grub_editenv=${bindir}/@grub_editenv@ ++etcdefaultgrub=/etc/default/grub ++ ++eval "$("${grub_get_kernel_settings}")" || true ++ ++EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g') ++if [ -d /sys/firmware/efi/efivars/ ]; then ++ startlink=/etc/grub2-efi.cfg ++ grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'` ++else ++ startlink=/etc/grub2.cfg ++ grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` ++fi ++ ++blsdir=`echo "/@bootdirname@/loader/entries" | sed 's,//*,/,g'` ++ ++backupsuffix=.bak ++ ++arch="$(uname -m)" ++ ++export TEXTDOMAIN=@PACKAGE@ ++export TEXTDOMAINDIR="@localedir@" ++ ++. "${pkgdatadir}/grub-mkconfig_lib" ++ ++# Usage: usage ++# Print the usage. ++usage () { ++ gettext_printf "Usage: %s\n" "$self" ++ gettext "Switch to BLS config files.\n"; echo ++ echo ++ print_option_help "-h, --help" "$(gettext "print this message and exit")" ++ print_option_help "-V, --version" "$(gettext "print the version information and exit")" ++ echo ++ print_option_help "--backup-suffix=$(gettext "SUFFIX")" "$backupsuffix" ++ print_option_help "--bls-directory=$(gettext "DIR")" "$blsdir" ++ print_option_help "--config-file=$(gettext "FILE")" "$startlink" ++ print_option_help "--grub-defaults=$(gettext "FILE")" "$etcdefaultgrub" ++ print_option_help "--grub-directory=$(gettext "DIR")" "$grubdir" ++ # echo ++ # gettext "Report bugs to ."; echo ++} ++ ++argument () { ++ opt=$1 ++ shift ++ ++ if test $# -eq 0; then ++ gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$opt" 1>&2 ++ exit 1 ++ fi ++ echo $1 ++} ++ ++# Check the arguments. ++while test $# -gt 0 ++do ++ option=$1 ++ shift ++ ++ case "$option" in ++ -h | --help) ++ usage ++ exit 0 ;; ++ -V | --version) ++ echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" ++ exit 0 ;; ++ ++ --backup-suffix) ++ backupsuffix=`argument $option "$@"` ++ shift ++ ;; ++ --backup-suffix=*) ++ backupsuffix=`echo "$option" | sed 's/--backup-suffix=//'` ++ ;; ++ ++ --bls-directory) ++ blsdir=`argument $option "$@"` ++ shift ++ ;; ++ --bls-directory=*) ++ blsdir=`echo "$option" | sed 's/--bls-directory=//'` ++ ;; ++ ++ --config-file) ++ startlink=`argument $option "$@"` ++ shift ++ ;; ++ --config-file=*) ++ startlink=`echo "$option" | sed 's/--config-file=//'` ++ ;; ++ ++ --grub-defaults) ++ etcdefaultgrub=`argument $option "$@"` ++ shift ++ ;; ++ --grub-defaults=*) ++ etcdefaultgrub=`echo "$option" | sed 's/--grub-defaults=//'` ++ ;; ++ ++ --grub-directory) ++ grubdir=`argument $option "$@"` ++ shift ++ ;; ++ --grub-directory=*) ++ grubdir=`echo "$option" | sed 's/--grub-directory=//'` ++ ;; ++ ++ *) ++ gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 ++ usage ++ exit 1 ++ ;; ++ esac ++done ++ ++find_grub_cfg() { ++ local candidate="" ++ while [ -e "${candidate}" -o $# -gt 0 ] ++ do ++ if [ ! -e "${candidate}" ] ; then ++ candidate="$1" ++ shift ++ fi ++ ++ if [ -L "${candidate}" ]; then ++ candidate="$(realpath "${candidate}")" ++ fi ++ ++ if [ -f "${candidate}" ]; then ++ export GRUB_CONFIG_FILE="${candidate}" ++ return 0 ++ fi ++ done ++ return 1 ++} ++ ++if ! find_grub_cfg ${startlink} ${grubdir}/grub.cfg ; then ++ gettext_printf "Couldn't find config file\n" 1>&2 ++ exit 1 ++fi ++ ++if [ ! -d "${blsdir}" ]; then ++ install -m 700 -d "${blsdir}" ++fi ++ ++if [ -f /etc/machine-id ]; then ++ MACHINE_ID=$(cat /etc/machine-id) ++else ++ MACHINE_ID=$(dmesg | sha256sum) ++fi ++ ++mkbls() { ++ local kernelver=$1 && shift ++ local datetime=$1 && shift ++ local kernelopts=$1 && shift ++ ++ local debugname="" ++ local debugid="" ++ local flavor="" ++ ++ if [ "$kernelver" == *\+* ] ; then ++ local flavor=-"${kernelver##*+}" ++ if [ "${flavor}" == "-debug" ]; then ++ local debugname=" with debugging" ++ local debugid="-debug" ++ fi ++ fi ++ ( ++ source /etc/os-release ++ ++ cat <"${bls_target}" ++ ++ if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then ++ bls_debug="$(echo ${bls_target} | sed -e "s/${kernelver}/${kernelver}~debug/")" ++ cp -aT "${bls_target}" "${bls_debug}" ++ title="$(grep '^title[ \t]' "${bls_debug}" | sed -e 's/^title[ \t]*//')" ++ options="$(echo "${cmdline} ${GRUB_CMDLINE_LINUX_DEBUG}" | sed -e 's/\//\\\//g')" ++ sed -i -e "s/^title.*/title ${title}${GRUB_LINUX_DEBUG_TITLE_POSTFIX}/" "${bls_debug}" ++ sed -i -e "s/^options.*/options ${options}/" "${bls_debug}" ++ fi ++ done ++ ++ if [ -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]; then ++ mkbls "0-rescue-${MACHINE_ID}" "0" "${bootprefix}" >"${blsdir}/${MACHINE_ID}-0-rescue.conf" ++ fi ++} ++ ++# The grub2 EFI binary is not copied to the ESP as a part of an ostree ++# transaction. Make sure a grub2 version with BLS support is installed ++# but only do this if the blsdir is not set, to make sure that the BLS ++# parsing module will search for the BLS snippets in the default path. ++if test -f /run/ostree-booted && test -d /sys/firmware/efi/efivars && \ ++ ! ${grub_editenv} - list | grep -q blsdir && \ ++ mountpoint -q /boot; then ++ grub_binary="$(find /usr/lib/ostree-boot/efi/EFI/${EFIDIR}/ -name grub*.efi)" ++ install -m 700 ${grub_binary} ${grubdir} || exit 1 ++ # Create a hidden file to indicate that grub2 now has BLS support. ++ touch /boot/grub2/.grub2-blscfg-supported ++fi ++ ++GENERATE=0 ++if grep '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" \ ++ | grep -vq '^GRUB_ENABLE_BLSCFG="*true"*\s*$' ; then ++ if ! sed -i"${backupsuffix}" \ ++ -e 's,^GRUB_ENABLE_BLSCFG=.*,GRUB_ENABLE_BLSCFG=true,' \ ++ "${etcdefaultgrub}" ; then ++ gettext_printf "Updating %s failed\n" "${etcdefaultgrub}" ++ exit 1 ++ fi ++ GENERATE=1 ++elif ! grep -q '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" ; then ++ if ! echo 'GRUB_ENABLE_BLSCFG=true' >> "${etcdefaultgrub}" ; then ++ gettext_printf "Updating %s failed\n" "${etcdefaultgrub}" ++ exit 1 ++ fi ++ GENERATE=1 ++fi ++ ++if [ "${GENERATE}" -eq 1 ] ; then ++ copy_bls ++ ++ if [ $arch = "x86_64" ] && [ ! -d /sys/firmware/efi ]; then ++ mod_dir="i386-pc" ++ elif [ $arch = "ppc64" -o $arch = "ppc64le" ] && [ ! -d /sys/firmware/opal ]; then ++ mod_dir="powerpc-ieee1275" ++ fi ++ ++ if [ -n "${mod_dir}" ]; then ++ for mod in blscfg increment; do ++ install -m 700 ${prefix}/lib/grub/${mod_dir}/${mod}.mod ${grubdir}/$mod_dir/ || exit 1 ++ done ++ fi ++ ++ cp -af "${GRUB_CONFIG_FILE}" "${GRUB_CONFIG_FILE}${backupsuffix}" ++ if ! grub2-mkconfig -o "${GRUB_CONFIG_FILE}" ; then ++ install -m 700 "${GRUB_CONFIG_FILE}${backupsuffix}" "${GRUB_CONFIG_FILE}" ++ sed -i"${backupsuffix}" \ ++ -e 's,^GRUB_ENABLE_BLSCFG=.*,GRUB_ENABLE_BLSCFG=false,' \ ++ "${etcdefaultgrub}" ++ gettext_printf "Updating %s failed\n" "${GRUB_CONFIG_FILE}" ++ exit 1 ++ fi ++fi ++ ++# Bye. ++exit 0 +diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in +index 6a316a5ba..3e1b77265 100644 +--- a/util/grub.d/00_header.in ++++ b/util/grub.d/00_header.in +@@ -27,6 +27,14 @@ export TEXTDOMAINDIR="@localedir@" + + . "$pkgdatadir/grub-mkconfig_lib" + ++if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] && ++ [ "x${GRUB_FS}" = "xbtrfs" ] ; then ++ cat </dev/null || true` +@@ -79,6 +84,255 @@ case x"$GRUB_FS" in + ;; + esac + ++populate_header_warn() ++{ ++if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then ++ bls_parser="10_linux script" ++else ++ bls_parser="blscfg command" ++fi ++cat </dev/null)) || : ++ ++ echo "${files[@]}" ++} ++ ++update_bls_cmdline() ++{ ++ local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" ++ local -a files=($(get_sorted_bls)) ++ ++ if [ -w /etc/kernel ] && ++ [[ ! -f /etc/kernel/cmdline || ++ /etc/kernel/cmdline -ot /etc/default/grub ]]; then ++ # anaconda has the correct information to create this during install; ++ # afterward, grubby will take care of syncing on updates. If the user ++ # has modified /etc/default/grub, try to cope. ++ echo "$cmdline" > /etc/kernel/cmdline ++ fi ++ ++ for bls in "${files[@]}"; do ++ local options="${cmdline}" ++ if [ -z "${bls##*debug*}" ]; then ++ options="${options} ${GRUB_CMDLINE_LINUX_DEBUG}" ++ fi ++ options="$(echo "${options}" | sed -e 's/\//\\\//g')" ++ sed -i -e "s/^options.*/options ${options}/" "${blsdir}/${bls}.conf" ++ done ++} ++ ++populate_menu() ++{ ++ local -a files=($(get_sorted_bls)) ++ ++ gettext_printf "Generating boot entries from BLS files...\n" >&2 ++ ++ for bls in "${files[@]}"; do ++ read_config "${blsdir}/${bls}.conf" ++ ++ menu="${menu}menuentry '${title}' ${grub_arg} --id=${bls} {\n" ++ menu="${menu}\t linux ${linux} ${options}\n" ++ if [ -n "${initrd}" ] ; then ++ menu="${menu}\t initrd ${boot_prefix}${initrd}\n" ++ fi ++ menu="${menu}}\n\n" ++ done ++ # The printf command seems to be more reliable across shells for special character (\n, \t) evaluation ++ printf "$menu" ++} ++ ++# Make BLS the default if GRUB_ENABLE_BLSCFG was not set and grubby is not installed. ++if [ -z "${GRUB_ENABLE_BLSCFG}" ] && ! command -v new-kernel-pkg >/dev/null; then ++ GRUB_ENABLE_BLSCFG="true" ++fi ++ ++if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]; then ++ if [ x$dirname = x/ ]; then ++ if [ -z "${prepare_root_cache}" ]; then ++ prepare_grub_to_access_device ${GRUB_DEVICE} ++ fi ++ else ++ if [ -z "${prepare_boot_cache}" ]; then ++ prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} ++ fi ++ fi ++ ++ if [ -d /sys/firmware/efi ]; then ++ bootefi_device="`${grub_probe} --target=device /boot/efi/`" ++ prepare_grub_to_access_device_with_variable boot ${bootefi_device} ++ else ++ boot_device="`${grub_probe} --target=device /boot/`" ++ prepare_grub_to_access_device_with_variable boot ${boot_device} ++ fi ++ ++ arch="$(uname -m)" ++ if [ "x${arch}" = "xppc64le" ] && [ -d /sys/firmware/opal ]; then ++ ++ BLS_POPULATE_MENU="true" ++ petitboot_path="/sys/firmware/devicetree/base/ibm,firmware-versions/petitboot" ++ ++ if test -e ${petitboot_path}; then ++ read -r -d '' petitboot_version < ${petitboot_path} ++ petitboot_version="$(echo ${petitboot_version//v})" ++ ++ if test -n ${petitboot_version}; then ++ major_version="$(echo ${petitboot_version} | cut -d . -f1)" ++ minor_version="$(echo ${petitboot_version} | cut -d . -f2)" ++ ++ re='^[0-9]+$' ++ if [[ $major_version =~ $re ]] && [[ $minor_version =~ $re ]] && ++ ([[ ${major_version} -gt 1 ]] || ++ [[ ${major_version} -eq 1 && ++ ${minor_version} -ge 8 ]]); then ++ BLS_POPULATE_MENU="false" ++ fi ++ fi ++ fi ++ fi ++ ++ populate_header_warn ++ ++ cat << EOF ++# The kernelopts variable should be defined in the grubenv file. But to ensure that menu ++# entries populated from BootLoaderSpec files that use this variable work correctly even ++# without a grubenv file, define a fallback kernelopts variable if this has not been set. ++# ++# The kernelopts variable in the grubenv file can be modified using the grubby tool or by ++# executing the grub2-mkconfig tool. For the latter, the values of the GRUB_CMDLINE_LINUX ++# and GRUB_CMDLINE_LINUX_DEFAULT options from /etc/default/grub file are used to set both ++# the kernelopts variable in the grubenv file and the fallback kernelopts variable. ++if [ -z "\${kernelopts}" ]; then ++ set kernelopts="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" ++fi ++EOF ++ ++ if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then ++ update_bls_cmdline ++ fi ++ ++ if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then ++ populate_menu ++ else ++ cat << EOF ++ ++insmod blscfg ++blscfg ++EOF ++ fi ++ ++ if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then ++ blsdir="/boot/loader/entries" ++ [ -d "${blsdir}" ] && GRUB_BLS_FS="$(${grub_probe} --target=fs ${blsdir})" ++ if [ "x${GRUB_BLS_FS}" = "xbtrfs" ] || [ "x${GRUB_BLS_FS}" = "xzfs" ]; then ++ blsdir=$(make_system_path_relative_to_its_root "${blsdir}") ++ if [ "x${blsdir}" != "x/loader/entries" ] && [ "x${blsdir}" != "x/boot/loader/entries" ]; then ++ ${grub_editenv} - set blsdir="${blsdir}" ++ fi ++ fi ++ ++ if [ -n "${GRUB_EARLY_INITRD_LINUX_CUSTOM}" ]; then ++ ${grub_editenv} - set early_initrd="${GRUB_EARLY_INITRD_LINUX_CUSTOM}" ++ fi ++ ++ if [ -n "${GRUB_DEFAULT_DTB}" ]; then ++ ${grub_editenv} - set devicetree="${GRUB_DEFAULT_DTB}" ++ fi ++ ++ if [ -n "${GRUB_SAVEDEFAULT}" ]; then ++ ${grub_editenv} - set save_default="${GRUB_SAVEDEFAULT}" ++ fi ++ fi ++ ++ exit 0 ++fi ++ ++mktitle () ++{ ++ local title_type ++ local version ++ local OS_NAME ++ local OS_VERS ++ ++ title_type=$1 && shift ++ version=$1 && shift ++ ++ OS_NAME="$(eval $(grep ^NAME= /etc/os-release) ; echo ${NAME})" ++ OS_VERS="$(eval $(grep ^VERSION= /etc/os-release) ; echo ${VERSION})" ++ ++ case $title_type in ++ recovery) ++ title=$(printf '%s (%s) %s (recovery mode)' \ ++ "${OS_NAME}" "${version}" "${OS_VERS}") ++ ;; ++ *) ++ title=$(printf '%s (%s) %s' \ ++ "${OS_NAME}" "${version}" "${OS_VERS}") ++ ;; ++ esac ++ echo -n ${title} ++} ++ + title_correction_code= + + linux_entry () +@@ -86,23 +340,22 @@ linux_entry () + os="$1" + version="$2" + type="$3" +- args="$4" ++ isdebug="$4" ++ args="$5" + + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi ++ + if [ x$type != xsimple ] ; then +- case $type in +- recovery) +- title="$(gettext_printf "%s, with Linux %s (recovery mode)" "${os}" "${version}")" ;; +- *) +- title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;; +- esac ++ title=$(mktitle "$type" "$version") + if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then + replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')" + quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)" + title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" +- grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")" ++ fi ++ if [ x$isdebug = xdebug ]; then ++ title="$title${GRUB_LINUX_DEBUG_TITLE_POSTFIX}" + fi + echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" + else +@@ -155,6 +408,13 @@ EOF + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' + initrd $(echo $initrd_path) ++EOF ++ fi ++ if test -n "${fdt}" ; then ++ message="$(gettext_printf "Loading fdt ...")" ++ sed "s/^/$submenu_indentation/" << EOF ++ echo '$(echo "$message" | grub_quote)' ++ devicetree ${rel_dirname}/${fdt} + EOF + fi + sed "s/^/$submenu_indentation/" << EOF +@@ -207,6 +467,7 @@ fi + is_top_level=true + for linux in ${reverse_sorted_list}; do + gettext_printf "Found linux image: %s\n" "$linux" >&2 ++ + basename=`basename $linux` + dirname=`dirname $linux` + rel_dirname=`make_system_path_relative_to_its_root $dirname` +@@ -247,9 +508,19 @@ for linux in ${reverse_sorted_list}; do + for i in ${initrd}; do + initrd_display="${initrd_display} ${dirname}/${i}" + done +- gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2 ++ if [ "x${GRUB_ENABLE_BLSCFG}" != "xtrue" ]; then ++ gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2 ++ fi + fi + ++ fdt= ++ for i in "dtb-${version}" "dtb-${alt_version}"; do ++ if test -f "${dirname}/${i}/${GRUB_DEFAULT_DTB}" ; then ++ fdt="${i}/${GRUB_DEFAULT_DTB}" ++ break ++ fi ++ done ++ + config= + for i in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do + if test -e "${i}" ; then +@@ -284,11 +555,15 @@ for linux in ${reverse_sorted_list}; do + fi + + if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then +- linux_entry "${OS}" "${version}" simple \ ++ linux_entry "${OS}" "${version}" simple standard \ + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" ++ if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then ++ linux_entry "${OS}" "${version}" simple debug \ ++ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}" ++ fi + + submenu_indentation="$grub_tab" +- ++ + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi +@@ -297,10 +572,15 @@ for linux in ${reverse_sorted_list}; do + is_top_level=false + fi + +- linux_entry "${OS}" "${version}" advanced \ ++ linux_entry "${OS}" "${version}" advanced standard \ + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" ++ if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then ++ linux_entry "${OS}" "${version}" advanced debug \ ++ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}" ++ fi ++ + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then +- linux_entry "${OS}" "${version}" recovery \ ++ linux_entry "${OS}" "${version}" recovery standard \ + "${GRUB_CMDLINE_LINUX_RECOVERY} ${GRUB_CMDLINE_LINUX}" + fi + done +diff --git a/util/grub.d/10_reset_boot_success.in b/util/grub.d/10_reset_boot_success.in +new file mode 100644 +index 000000000..e73f4137b +--- /dev/null ++++ b/util/grub.d/10_reset_boot_success.in +@@ -0,0 +1,25 @@ ++#! /bin/sh -e ++# Reset Boot Success ++# ++# The 08_fallback_counting and 12_menu_auto_hide snippets rely on this one ++# and need to be kept in sync. ++# ++# The boot_success var needs to be set to 1 from userspace to mark a boot successful. ++cat << EOF ++# Hiding the menu is ok if last boot was ok or if this is a first boot attempt to boot the entry ++if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then ++ set menu_hide_ok=1 ++else ++ set menu_hide_ok=0 ++fi ++# Reset boot_indeterminate after a successful boot ++if [ "\${boot_success}" = "1" ] ; then ++ set boot_indeterminate=0 ++# Avoid boot_indeterminate causing the menu to be hidden more than once ++elif [ "\${boot_indeterminate}" = "1" ]; then ++ set boot_indeterminate=2 ++fi ++# Reset boot_success for current boot ++set boot_success=0 ++save_env boot_success boot_indeterminate ++EOF +diff --git a/util/grub.d/12_menu_auto_hide.in b/util/grub.d/12_menu_auto_hide.in +new file mode 100644 +index 000000000..6a7c0fa0d +--- /dev/null ++++ b/util/grub.d/12_menu_auto_hide.in +@@ -0,0 +1,35 @@ ++#! /bin/sh ++# Menu Auto Hide ++# ++# This snippet depends on 10_reset_boot_success and needs to be kept in sync. ++# ++# Disable / skip generating menu-auto-hide config parts on serial terminals ++for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do ++ case "$x" in ++ serial*) ++ exit 0 ++ ;; ++ esac ++done ++ ++cat << EOF ++if [ x\$feature_timeout_style = xy ] ; then ++ if [ "\${menu_show_once}" ]; then ++ unset menu_show_once ++ save_env menu_show_once ++ set timeout_style=menu ++ set timeout=60 ++ elif [ "\${menu_auto_hide}" -a "\${menu_hide_ok}" = "1" ]; then ++ set orig_timeout_style=\${timeout_style} ++ set orig_timeout=\${timeout} ++ if [ "\${fastboot}" = "1" ]; then ++ # timeout_style=menu + timeout=0 avoids the countdown code keypress check ++ set timeout_style=menu ++ set timeout=0 ++ else ++ set timeout_style=hidden ++ set timeout=1 ++ fi ++ fi ++fi ++EOF +diff --git a/util/grub.d/14_menu_show_once.in b/util/grub.d/14_menu_show_once.in +new file mode 100755 +index 000000000..1cd7f3614 +--- /dev/null ++++ b/util/grub.d/14_menu_show_once.in +@@ -0,0 +1,13 @@ ++#! /bin/sh ++# Force the menu to be shown once, with a timeout of ${menu_show_once_timeout} ++# if requested by ${menu_show_once_timeout} being set in the env. ++cat << EOF ++if [ x\$feature_timeout_style = xy ]; then ++ if [ "\${menu_show_once_timeout}" ]; then ++ set timeout_style=menu ++ set timeout="\${menu_show_once_timeout}" ++ unset menu_show_once_timeout ++ save_env menu_show_once_timeout ++ fi ++fi ++EOF +diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in +index 94dd8be13..4ecf5deea 100644 +--- a/util/grub.d/20_linux_xen.in ++++ b/util/grub.d/20_linux_xen.in +@@ -29,9 +29,9 @@ export TEXTDOMAINDIR="@localedir@" + CLASS="--class gnu-linux --class gnu --class os --class xen" + + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then +- OS=GNU/Linux ++ OS="$(sed 's, release .*$,,g' /etc/system-release)" + else +- OS="${GRUB_DISTRIBUTOR} GNU/Linux" ++ OS="${GRUB_DISTRIBUTOR}" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}" + fi + +@@ -75,10 +75,14 @@ fi + + case x"$GRUB_FS" in + xbtrfs) ++ if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ]; then ++ GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX} \${extra_cmdline}" ++ else + rootsubvol="`make_system_path_relative_to_its_root /`" + rootsubvol="${rootsubvol#/}" + if [ "x${rootsubvol}" != x ]; then + GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}" ++ fi + fi;; + xzfs) + rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true` +@@ -152,6 +156,7 @@ linux_entry_xsm () + else + xen_rm_opts="no-real-mode edd=off" + fi ++ insmod ${xen_module} + ${xen_loader} ${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} \${xen_rm_opts} + echo '$(echo "$lmessage" | grub_quote)' + ${module_loader} ${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args} +@@ -164,6 +169,7 @@ EOF + initrd_path="${rel_dirname}/${i}" + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' ++ insmod ${xen_module} + ${module_loader} --nounzip $(echo $initrd_path) + EOF + done +@@ -265,13 +271,16 @@ for current_xen in ${reverse_sorted_xen_list}; do + echo " submenu '$(gettext_printf "Xen hypervisor, version %s" "${xen_version}" | grub_quote)' \$menuentry_id_option 'xen-hypervisor-$xen_version-$boot_device_id' {" + fi + if ($grub_file --is-arm64-efi $current_xen); then ++ xen_module="xen_boot" + xen_loader="xen_hypervisor" + module_loader="xen_module" + else + if ($grub_file --is-x86-multiboot2 $current_xen); then ++ xen_module="multiboot2" + xen_loader="multiboot2" + module_loader="module2" + else ++ xen_module="multiboot" + xen_loader="multiboot" + module_loader="module" + fi +diff --git a/util/grub.d/20_ppc_terminfo.in b/util/grub.d/20_ppc_terminfo.in +new file mode 100644 +index 000000000..10d665868 +--- /dev/null ++++ b/util/grub.d/20_ppc_terminfo.in +@@ -0,0 +1,114 @@ ++#! /bin/sh ++set -e ++ ++# grub-mkconfig helper script. ++# Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. ++# ++# GRUB is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# GRUB 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 General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with GRUB. If not, see . ++ ++prefix=@prefix@ ++exec_prefix=@exec_prefix@ ++bindir=@bindir@ ++libdir=@libdir@ ++. "@datadir@/@PACKAGE@/grub-mkconfig_lib" ++ ++export TEXTDOMAIN=@PACKAGE@ ++export TEXTDOMAINDIR=@localedir@ ++ ++X=80 ++Y=24 ++TERMINAL=ofconsole ++ ++argument () { ++ opt=$1 ++ shift ++ ++ if test $# -eq 0; then ++ echo "$0: option requires an argument -- '$opt'" 1>&2 ++ exit 1 ++ fi ++ echo $1 ++} ++ ++check_terminfo () { ++ ++ while test $# -gt 0 ++ do ++ option=$1 ++ shift ++ ++ case "$option" in ++ terminfo | TERMINFO) ++ ;; ++ ++ -g) ++ NEWXY=`argument $option "$@"` ++ NEWX=`echo $NEWXY | cut -d x -f 1` ++ NEWY=`echo $NEWXY | cut -d x -f 2` ++ ++ if [ ${NEWX} -ge 80 ] ; then ++ X=${NEWX} ++ else ++ echo "Warning: ${NEWX} is less than the minimum size of 80" ++ fi ++ ++ if [ ${NEWY} -ge 24 ] ; then ++ Y=${NEWY} ++ else ++ echo "Warning: ${NEWY} is less than the minimum size of 24" ++ fi ++ ++ shift ++ ;; ++ ++ *) ++# # accept console or ofconsole ++# if [ "$option" != "console" -a "$option" != "ofconsole" ] ; then ++# echo "Error: GRUB_TERMINFO unknown console: $option" ++# exit 1 ++# fi ++# # perfer console ++# TERMINAL=console ++ # accept ofconsole ++ if [ "$option" != "ofconsole" ] ; then ++ echo "Error: GRUB_TERMINFO unknown console: $option" ++ exit 1 ++ fi ++ # perfer console ++ TERMINAL=ofconsole ++ ;; ++ esac ++ ++ done ++ ++} ++ ++if ! uname -m | grep -q ppc ; then ++ exit 0 ++fi ++ ++if [ "x${GRUB_TERMINFO}" != "x" ] ; then ++ F1=`echo ${GRUB_TERMINFO} | cut -d " " -f 1` ++ ++ if [ "${F1}" != "terminfo" ] ; then ++ echo "Error: GRUB_TERMINFO is set to \"${GRUB_TERMINFO}\" The first word should be terminfo." ++ exit 1 ++ fi ++ ++ check_terminfo ${GRUB_TERMINFO} ++fi ++ ++cat << EOF ++ terminfo -g ${X}x${Y} ${TERMINAL} ++EOF +diff --git a/util/grub.d/25_bli.in b/util/grub.d/25_bli.in +index 26e27a019..00a8d7159 100644 +--- a/util/grub.d/25_bli.in ++++ b/util/grub.d/25_bli.in +@@ -19,6 +19,8 @@ set -e + + cat << EOF + if [ "\$grub_platform" = "efi" ]; then +- insmod bli ++ if [ ! insmod bli ]; then ++ echo "bli module not available" ++ fi + fi + EOF +diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in +index 656301eaf..18fe02cef 100644 +--- a/util/grub.d/30_os-prober.in ++++ b/util/grub.d/30_os-prober.in +@@ -27,7 +27,6 @@ export TEXTDOMAINDIR="@localedir@" + . "$pkgdatadir/grub-mkconfig_lib" + + if [ "x${GRUB_DISABLE_OS_PROBER}" = "xtrue" ]; then +- grub_warn "$(gettext_printf "os-prober will not be executed to detect other bootable partitions.\nSystems on them will not be added to the GRUB boot configuration.\nCheck GRUB_DISABLE_OS_PROBER documentation entry.")" + exit 0 + fi + +@@ -36,8 +35,6 @@ if ! command -v os-prober > /dev/null || ! command -v linux-boot-prober > /dev/n + exit 0 + fi + +-grub_warn "$(gettext_printf "os-prober will be executed to detect other bootable partitions.\nIts output will be used to detect bootable binaries on them and create new boot entries.")" +- + OSPROBED="`os-prober | tr ' ' '^' | paste -s -d ' '`" + if [ -z "${OSPROBED}" ] ; then + # empty os-prober output, nothing doing +@@ -45,68 +42,26 @@ if [ -z "${OSPROBED}" ] ; then + fi + + osx_entry() { +- if [ x$2 = x32 ]; then +- # TRANSLATORS: it refers to kernel architecture (32-bit) +- bitstr="$(gettext "(32-bit)")" +- else +- # TRANSLATORS: it refers to kernel architecture (64-bit) +- bitstr="$(gettext "(64-bit)")" +- fi ++ found_other_os=1 + # TRANSLATORS: it refers on the OS residing on device %s + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" +- cat << EOF +-menuentry '$(echo "${LONGNAME} $bitstr $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")' { ++ hints="" ++ for hint in `"${grub_probe}" --device ${device} --target=efi_hints 2> /dev/null` ; do ++ hints="${hints} --hint=${hint}" ++ done ++ cat << EOF ++menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")' { + EOF + save_default_entry | grub_add_tab + prepare_grub_to_access_device ${DEVICE} | grub_add_tab + cat << EOF ++ set gfxpayload=keep + load_video +- set do_resume=0 +- if [ /var/vm/sleepimage -nt10 / ]; then +- if xnu_resume /var/vm/sleepimage; then +- set do_resume=1 +- fi +- fi +- if [ \$do_resume = 0 ]; then +- xnu_uuid ${OSXUUID} uuid +- if [ -f /Extra/DSDT.aml ]; then +- acpi -e /Extra/DSDT.aml +- fi +- if [ /kernelcache -nt /System/Library/Extensions ]; then +- $1 /kernelcache boot-uuid=\${uuid} rd=*uuid +- elif [ -f /System/Library/Kernels/kernel ]; then +- $1 /System/Library/Kernels/kernel boot-uuid=\${uuid} rd=*uuid +- xnu_kextdir /System/Library/Extensions +- else +- $1 /mach_kernel boot-uuid=\${uuid} rd=*uuid +- if [ /System/Library/Extensions.mkext -nt /System/Library/Extensions ]; then +- xnu_mkext /System/Library/Extensions.mkext +- else +- xnu_kextdir /System/Library/Extensions +- fi +- fi +- if [ -f /Extra/Extensions.mkext ]; then +- xnu_mkext /Extra/Extensions.mkext +- fi +- if [ -d /Extra/Extensions ]; then +- xnu_kextdir /Extra/Extensions +- fi +- if [ -f /Extra/devprop.bin ]; then +- xnu_devprop_load /Extra/devprop.bin +- fi +- if [ -f /Extra/splash.jpg ]; then +- insmod jpeg +- xnu_splash /Extra/splash.jpg +- fi +- if [ -f /Extra/splash.png ]; then +- insmod png +- xnu_splash /Extra/splash.png +- fi +- if [ -f /Extra/splash.tga ]; then +- insmod tga +- xnu_splash /Extra/splash.tga +- fi +- fi ++ insmod part_gpt ++ insmod hfsplus ++ search --no-floppy --fs-uuid --set=root ${hints} $(grub_get_device_id "${DEVICE}") ++ chainloader (\$root)/System/Library/CoreServices/boot.efi ++ boot + } + EOF + } +@@ -152,6 +107,7 @@ for OS in ${OSPROBED} ; do + + case ${BOOT} in + chain) ++ found_other_os=1 + + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + cat << EOF +@@ -182,6 +138,7 @@ EOF + EOF + ;; + efi) ++ found_other_os=1 + + EFIPATH=${DEVICE#*@} + DEVICE=${DEVICE%@*} +@@ -226,6 +183,7 @@ EOF + LINITRD="${LINITRD#/boot}" + fi + ++ found_other_os=1 + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + recovery_params="$(echo "${LPARAMS}" | grep single)" || true + counter=1 +@@ -299,13 +257,15 @@ EOF + echo "$title_correction_code" + ;; + macosx) +- if [ "${UUID}" ]; then +- OSXUUID="${UUID}" +- osx_entry xnu_kernel 32 +- osx_entry xnu_kernel64 64 +- fi ++ for subdevice in ${DEVICE%[[:digit:]]*}* ; do ++ parttype="`"${grub_probe}" --device ${device} --target=gpt_parttype "${subdevice}" 2> /dev/null`" ++ if [[ "$parttype" = "426f6f74-0000-11aa-aa11-00306543ecac" ]]; then ++ DEVICE="${subdevice}" osx_entry ++ fi ++ done + ;; + hurd) ++ found_other_os=1 + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + cat << EOF + menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' { +@@ -332,6 +292,7 @@ EOF + EOF + ;; + minix) ++ found_other_os=1 + cat << EOF + menuentry "${LONGNAME} (on ${DEVICE}, Multiboot)" { + EOF +@@ -348,3 +309,15 @@ EOF + ;; + esac + done ++ ++# We override the results of the menu_auto_hide code here, this is a bit ugly, ++# but grub-mkconfig writes out the file linearly, so this is the only way ++if [ "${found_other_os}" = "1" ]; then ++ cat << EOF ++# Other OS found, undo autohiding of menu unless menu_auto_hide=2 ++if [ "\${orig_timeout_style}" -a "\${menu_auto_hide}" != "2" ]; then ++ set timeout_style=\${orig_timeout_style} ++ set timeout=\${orig_timeout} ++fi ++EOF ++fi +diff --git a/util/grub.d/30_uefi-firmware.in b/util/grub.d/30_uefi-firmware.in +index 1c2365ddb..1ef31e08f 100644 +--- a/util/grub.d/30_uefi-firmware.in ++++ b/util/grub.d/30_uefi-firmware.in +@@ -32,8 +32,7 @@ gettext_printf "Adding boot menu entry for UEFI Firmware Settings ...\n" >&2 + + cat << EOF + if [ "\$grub_platform" = "efi" ]; then +- fwsetup --is-supported +- if [ "\$?" = 0 ]; then ++ if [ fwsetup --is-supported ]; then + menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' { + fwsetup + } +diff --git a/util/mkimage.c b/util/mkimage.c +index 4237383ac..425d920ff 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -883,10 +883,12 @@ void + grub_install_generate_image (const char *dir, const char *prefix, + FILE *out, const char *outname, char *mods[], + char *memdisk_path, char **pubkey_paths, +- size_t npubkeys, char *config_path, ++ size_t npubkeys, char **x509key_paths, ++ size_t nx509keys, char *config_path, + const struct grub_install_image_target_desc *image_target, +- int note, grub_compression_t comp, const char *dtb_path, +- const char *sbat_path, int disable_shim_lock) ++ int note, size_t appsig_size, grub_compression_t comp, ++ const char *dtb_path, const char *sbat_path, ++ int disable_shim_lock) + { + char *kernel_img, *core_img; + size_t total_module_size, core_size; +@@ -928,6 +930,19 @@ grub_install_generate_image (const char *dir, const char *prefix, + } + } + ++ { ++ size_t i; ++ for (i = 0; i < nx509keys; i++) ++ { ++ size_t curs; ++ curs = ALIGN_ADDR (grub_util_get_image_size (x509key_paths[i])); ++ grub_util_info ("the size of x509 public key %u is 0x%" ++ GRUB_HOST_PRIxLONG_LONG, ++ (unsigned) i, (unsigned long long) curs); ++ total_module_size += curs + sizeof (struct grub_module_header); ++ } ++ } ++ + if (memdisk_path) + { + memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512); +@@ -1049,7 +1064,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + curs = grub_util_get_image_size (pubkey_paths[i]); + + header = (struct grub_module_header *) (kernel_img + offset); +- header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY); ++ header->type = grub_host_to_target32 (OBJ_TYPE_GPG_PUBKEY); + header->size = grub_host_to_target32 (curs + sizeof (*header)); + offset += sizeof (*header); + +@@ -1058,6 +1073,26 @@ grub_install_generate_image (const char *dir, const char *prefix, + } + } + ++ { ++ size_t i; ++ for (i = 0; i < nx509keys; i++) ++ { ++ size_t curs; ++ struct grub_module_header *header; ++ ++ curs = grub_util_get_image_size (x509key_paths[i]); ++ ++ header = (struct grub_module_header *) (kernel_img + offset); ++ header->type = grub_host_to_target32 (OBJ_TYPE_X509_PUBKEY); ++ header->size = grub_host_to_target32 (curs + sizeof (*header)); ++ offset += sizeof (*header); ++ ++ grub_util_load_image (x509key_paths[i], kernel_img + offset); ++ offset += ALIGN_ADDR (curs); ++ } ++ } ++ ++ + if (memdisk_path) + { + struct grub_module_header *header; +@@ -1403,6 +1438,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdangling-pointer" + #endif ++ PE_OHDR (o32, o64, dll_characteristics) = grub_host_to_target16 (GRUB_PE32_NX_COMPAT); + PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); + PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address); + PE_OHDR (o32, o64, image_base) = 0; +@@ -1810,11 +1846,11 @@ grub_install_generate_image (const char *dir, const char *prefix, + else + target_addr = image_target->link_addr; + if (image_target->voidp_sizeof == 4) +- grub_mkimage_generate_elf32 (image_target, note, &core_img, &core_size, +- target_addr, &layout); ++ grub_mkimage_generate_elf32 (image_target, note, appsig_size, &core_img, ++ &core_size, target_addr, &layout); + else +- grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size, +- target_addr, &layout); ++ grub_mkimage_generate_elf64 (image_target, note, appsig_size, &core_img, ++ &core_size, target_addr, &layout); + } + break; + } +diff --git a/util/setup.c b/util/setup.c +index 87a889ff7..7aab468b0 100644 +--- a/util/setup.c ++++ b/util/setup.c +@@ -406,7 +406,7 @@ SETUP (const char *dir, + int is_ldm; + grub_err_t err; + grub_disk_addr_t *sectors; +- int i; ++ unsigned int i; + grub_fs_t fs; + unsigned int nsec, maxsec; + +diff --git a/util/systemd/10-grub-logind-service.conf.in b/util/systemd/10-grub-logind-service.conf.in +new file mode 100644 +index 000000000..f2d4ac007 +--- /dev/null ++++ b/util/systemd/10-grub-logind-service.conf.in +@@ -0,0 +1,2 @@ ++[Service] ++Environment=SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU=true +diff --git a/util/systemd/grub-systemd-integration.service.in b/util/systemd/grub-systemd-integration.service.in +new file mode 100644 +index 000000000..c81fb594c +--- /dev/null ++++ b/util/systemd/grub-systemd-integration.service.in +@@ -0,0 +1,8 @@ ++[Unit] ++Description=Grub2 systemctl reboot --boot-loader-menu=... support ++Before=umount.target systemd-reboot.service ++DefaultDependencies=no ++ConditionPathExists=/run/systemd/reboot-to-boot-loader-menu ++ ++[Service] ++ExecStart=@libexecdir@/@grubdirname@/systemd-integration.sh +diff --git a/util/systemd/systemd-integration.sh.in b/util/systemd/systemd-integration.sh.in +new file mode 100644 +index 000000000..a4c071c5b +--- /dev/null ++++ b/util/systemd/systemd-integration.sh.in +@@ -0,0 +1,11 @@ ++#!/bin/sh ++ ++TIMEOUT_USEC=$(cat /run/systemd/reboot-to-boot-loader-menu) ++TIMEOUT=$(((TIMEOUT_USEC + 500000) / 1000000)) ++ ++@grub_editenv@ - set menu_show_once_timeout=$TIMEOUT ++ ++# Downstream RH / Fedora patch for compatibility with old, not (yet) ++# regenerated grub.cfg files which miss the menu_show_once_timeout check ++# this older grubenv variable leads to a fixed timeout of 60 seconds ++@grub_editenv@ - set menu_show_once=1 diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-01-execute-return-code.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-01-execute-return-code.patch new file mode 100644 index 00000000000..fe8bfef6ddf --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-01-execute-return-code.patch @@ -0,0 +1,112 @@ +From 442b676110c35caedb57408c4a27a6ef74f4c7db Mon Sep 17 00:00:00 2001 +From: James Le Cuirot +Date: Thu, 24 Oct 2024 14:42:46 +0100 +Subject: [PATCH 1/2] script/execute: Don't let trailing blank lines determine + the return code + +grub_script_execute_sourcecode() parses and executes code one line at a +time, updating the return code each time because only the last line +determines the final status. However, trailing new lines were also +executed, masking any failure on the previous line. Fix this by only +trying to execute the command when there is actually one present. + +This has presumably never been noticed because this code is not used by +regular functions, only in special cases like eval and menu entries. The +latter generally don't return at all, having booted an OS. When failing +to boot, upstream GRUB triggers the fallback mechanism regardless of the +return code. + +We noticed the problem while using Red Hat's patches, which change this +behaviour to take account of the return code. In that case, a failure +takes you back to the menu rather than triggering a fallback. + +Signed-off-by: James Le Cuirot +--- + grub-core/script/execute.c | 5 ++++- + tests/grub_script_eval.in | 10 +++++++++- + 2 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c +index c19b4bf70..e369e8318 100644 +--- a/grub-core/script/execute.c ++++ b/grub-core/script/execute.c +@@ -935,7 +935,10 @@ grub_script_execute_sourcecode (const char *source) + break; + } + +- ret = grub_script_execute (parsed_script); ++ /* Don't let trailing blank lines determine the return code. */ ++ if (parsed_script->cmd) ++ ret = grub_script_execute (parsed_script); ++ + grub_script_free (parsed_script); + grub_free (line); + } +diff --git a/tests/grub_script_eval.in b/tests/grub_script_eval.in +index c97b78d77..9c6211042 100644 +--- a/tests/grub_script_eval.in ++++ b/tests/grub_script_eval.in +@@ -3,4 +3,12 @@ + eval echo "Hello world" + valname=tst + eval $valname=hi +-echo $tst +\ No newline at end of file ++echo $tst ++ ++if eval " ++false ++"; then ++ echo should have failed ++else ++ echo failed as expected ++fi +-- +2.46.1 + + +From 93eedb6cebe758db09066e084ddd2fb659ebc4fb Mon Sep 17 00:00:00 2001 +From: James Le Cuirot +Date: Thu, 24 Oct 2024 15:00:26 +0100 +Subject: [PATCH 2/2] normal/menu: Check return code of the script when + executing a menu entry + +Don't rely on grub_errno here because grub_script_execute_new_scope() +calls grub_print_error(), which always resets grub_errno back to +GRUB_ERR_NONE. It may also get reset by grub_wait_after_message(). + +This problem was observed when a "bad signature" error resulted in the +menu being redisplayed rather than the fallback mechanism being +triggered, although another change was also needed to fix it. This only +happens with Red Hat's patches because upstream GRUB triggers the +fallback mechanism regardless of the return code. + +Signed-off-by: James Le Cuirot +--- + grub-core/normal/menu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index cda10fa8b..fd9b8c6d8 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -376,14 +376,14 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + if (ptr && ptr[0] && ptr[1]) + grub_env_set ("default", ptr + 1); + +- grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args); ++ err = grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args); + + if (errs_before != grub_err_printed_errors) + grub_wait_after_message (); + + errs_before = grub_err_printed_errors; + +- if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) ++ if (err == GRUB_ERR_NONE && grub_loader_is_loaded ()) + /* Implicit execution of boot, only if something is loaded. */ + err = grub_command_execute ("boot", 0, 0); + +-- +2.46.1 + diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-add-verity-hash.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-add-verity-hash.patch index 8b90a00daa2..2a7f5064ed1 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-add-verity-hash.patch +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-add-verity-hash.patch @@ -16,9 +16,9 @@ Signed-off-by: Sayan Chowdhury --- diff -Naur a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c ---- a/grub-core/loader/efi/linux.c 2023-10-03 12:21:48.000000000 -0000 -+++ b/grub-core/loader/efi/linux.c 2024-09-12 10:18:36.454803371 -0000 -@@ -34,6 +34,8 @@ +--- a/grub-core/loader/efi/linux.c 2024-09-05 16:04:35.466205483 -0000 ++++ b/grub-core/loader/efi/linux.c 2024-09-05 16:54:36.760503901 -0000 +@@ -38,6 +38,8 @@ #include #include @@ -27,9 +27,9 @@ diff -Naur a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c GRUB_MOD_LICENSE ("GPLv3+"); static grub_dl_t my_mod; -@@ -533,7 +535,8 @@ - - grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); +@@ -833,7 +835,8 @@ + kernel = NULL; + #endif - cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); + cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE) @@ -37,7 +37,7 @@ diff -Naur a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c linux_args = grub_malloc (cmdline_size); if (!linux_args) { -@@ -550,6 +553,7 @@ +@@ -850,6 +853,7 @@ if (grub_errno == GRUB_ERR_NONE) { @@ -45,29 +45,64 @@ diff -Naur a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c grub_loader_set (grub_linux_boot, grub_linux_unload, 0); loaded = 1; } -diff -Naur a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c ---- a/grub-core/loader/i386/linux.c 2023-10-03 12:21:48.000000000 -0000 -+++ b/grub-core/loader/i386/linux.c 2024-09-12 10:28:05.571587951 -0000 +diff -Naur a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +--- a/grub-core/loader/i386/efi/linux.c 2024-09-11 15:08:38.463525457 -0000 ++++ b/grub-core/loader/i386/efi/linux.c 2024-09-11 15:10:30.732085424 -0000 +@@ -31,6 +31,8 @@ + #include + #include + ++#include ++ + GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; +@@ -466,7 +468,7 @@ + grub_dprintf ("linux", "new lh is at %p\n", lh); + + grub_dprintf ("linux", "setting up cmdline\n"); +- cmdline = kernel_alloc (KERNEL_MEM, lh->cmdline_size + 1, ++ cmdline = kernel_alloc (KERNEL_MEM, lh->cmdline_size + 1 + VERITY_CMDLINE_LENGTH, + GRUB_EFI_LOADER_DATA, + N_("can't allocate cmdline")); + if (!cmdline) +@@ -479,6 +481,9 @@ + lh->cmdline_size - (sizeof (LINUX_IMAGE) - 1), + GRUB_VERIFY_KERNEL_CMDLINE); + ++ grub_pass_verity_hash (kernel, cmdline + sizeof (LINUX_IMAGE) - 1, ++ lh->cmdline_size - (sizeof (LINUX_IMAGE) - 1) + VERITY_CMDLINE_LENGTH); ++ + grub_dprintf ("linux", "cmdline:%s\n", cmdline); + grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", + LOW_U32(cmdline)); +diff -Naur a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c +--- a/grub-core/loader/i386/pc/linux.c 2024-09-11 15:08:38.464525462 -0000 ++++ b/grub-core/loader/i386/pc/linux.c 2024-09-11 15:12:26.552628521 -0000 @@ -38,6 +38,8 @@ - #include #include + #include +#include + GRUB_MOD_LICENSE ("GPLv3+"); - #ifdef GRUB_MACHINE_PCBIOS -@@ -1018,6 +1020,7 @@ - goto fail; - } + #define GRUB_LINUX_CL_OFFSET 0x9000 +@@ -358,6 +360,11 @@ + if (err) + goto fail; -+ grub_pass_verity_hash (&lh, linux_cmdline, maximal_cmdline_size); - len = prot_file_size; - if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno) - grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), ++ grub_pass_verity_hash (&lh, ++ (char *)grub_linux_real_chunk ++ + GRUB_LINUX_CL_OFFSET + sizeof (LINUX_IMAGE) - 1, ++ maximal_cmdline_size); ++ + if (grub_linux_is_bzimage) + grub_linux_prot_target = GRUB_LINUX_BZIMAGE_ADDR; + else diff -Naur a/include/grub/verity-hash.h b/include/grub/verity-hash.h --- a/include/grub/verity-hash.h 1970-01-01 00:00:00.000000000 -0000 -+++ b/include/grub/verity-hash.h 2024-09-12 10:18:39.993826952 -0000 ++++ b/include/grub/verity-hash.h 2024-09-11 15:07:54.473295324 -0000 @@ -0,0 +1,51 @@ +/* CoreOS verity hash */ + diff --git a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/make.defaults b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/make.defaults index 8cbfe510c7a..d339b275f8b 100644 --- a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/make.defaults +++ b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/make.defaults @@ -56,10 +56,9 @@ USE="${USE} bindist" # no-source-code - license for sys-kernel/coreos-firmware # linux-fw-redistributable - license for sys-kernel/coreos-firmware # freedist - license for sys-kernel/coreos-kernel -# BSD-2-Clause-Patent - license for sys-firmware/edk2-aarch64 # intel-ucode - license for sys-firmware/intel-microcode ACCEPT_LICENSE="${ACCEPT_LICENSE} no-source-code - linux-fw-redistributable freedist BSD-2-Clause-Patent intel-ucode" + linux-fw-redistributable freedist intel-ucode" # Favor our own mirrors over Gentoo's GENTOO_MIRRORS=" diff --git a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.accept_keywords b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.accept_keywords index f665b05bf77..0ab6c2b67bf 100644 --- a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.accept_keywords +++ b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.accept_keywords @@ -53,8 +53,10 @@ # The only available ebuild (from GURU) has ~amd64 and no keyword for arm64 yet. =app-crypt/clevis-19-r1 ** +# Needed in SDK for Secure Boot. +=app-emulation/virt-firmware-24.7 ~amd64 ~arm64 + # Needed by arm64-native SDK. -=app-crypt/efitools-1.9.2-r1 ~arm64 =app-emulation/open-vmdk-1.0 * # Keep versions on both arches in sync. @@ -105,7 +107,7 @@ =sys-apps/zram-generator-1.1.2 ~arm64 # Upgrade to latest version for secureboot -=sys-boot/mokutil-0.6.0 ~amd64 +=sys-boot/mokutil-0.6.0 ~amd64 ~arm64 # Enable ipvsadm for arm64. =sys-cluster/ipvsadm-1.31-r1 ~arm64 @@ -118,3 +120,11 @@ # Needed by updated app-containers/containers-common =sys-fs/fuse-overlayfs-1.14 ~amd64 ~arm64 + +# azure-keyvault-pkcs11 +=app-crypt/azure-keyvault-pkcs11-0_p20240923 ~amd64 +=app-crypt/p11-kit-0.25.5 ~amd64 +=dev-cpp/azure-core-1.14.0 ~amd64 +=dev-cpp/azure-security-keyvault-certificates-4.2.1 ~amd64 +=dev-cpp/azure-security-keyvault-keys-4.4.1 ~amd64 +=dev-cpp/azure-identity-1.10.0 ~amd64 diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/shim-signed/Manifest b/sdk_container/src/third_party/coreos-overlay/sys-boot/shim-signed/Manifest new file mode 100644 index 00000000000..01961010c96 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/shim-signed/Manifest @@ -0,0 +1,2 @@ +DIST shimaa64-15.8.efi.signed 995206 BLAKE2B fc858188d800dd785a6b989f154ddb3bb07748b8ee91ec3ffbabddf7452bb12eecfb788d9df97d1d900395c0825a4336f8b428bafa978d31995c0f671b7d1726 SHA512 d7875c906b715819b8d1b2a3a79adce64e4b37cfd7d8164cdf76fbb73a8e0b8264b01c403f8d71869f7a78bb5f840e81061f41d75d85cb49c58d3bee5e65004c +DIST shimx64-15.8.efi.signed 948418 BLAKE2B 7c92989ec63111799cc0f481cef47108e58f96dc3b53116e1cee1e24cc940d3e5470a0aa6c057d86339f435eddc22272281c08e46db0856ada6db69d7cd32c64 SHA512 ff6e4f4add5c9d3914118e53e2669b7f63168c41be95b07c5a8308c64bf1a1d4ff133bb0dde602f0a0c7ef035e4847eac14969c3d9ff3a99c9011c2d8dd20014 diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/shim-signed/metadata.xml b/sdk_container/src/third_party/coreos-overlay/sys-boot/shim-signed/metadata.xml new file mode 100644 index 00000000000..408e4b227de --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/shim-signed/metadata.xml @@ -0,0 +1,8 @@ + + + + + cpe:/a:redhat:shim + rhboot/shim + + diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/shim-signed/shim-signed-15.8.ebuild b/sdk_container/src/third_party/coreos-overlay/sys-boot/shim-signed/shim-signed-15.8.ebuild new file mode 100644 index 00000000000..113f9d1c9c1 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/shim-signed/shim-signed-15.8.ebuild @@ -0,0 +1,25 @@ +# Copyright (c) 2024 The Flatcar Maintainers. +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +declare -A ARCHES +ARCHES[amd64]="x64" +ARCHES[arm64]="aa64" + +DESCRIPTION="Signed UEFI Shim loader" +HOMEPAGE="https://github.com/rhboot/shim" +S="${WORKDIR}" + +LICENSE="BSD" +SLOT="0" +KEYWORDS="amd64 arm64" + +for arch in ${KEYWORDS}; do + SRC_URI+="${arch}? ( https://mirror.release.flatcar-linux.net/coreos/shim${ARCHES[$arch]}-${PV}.efi.signed ) " +done + +src_install() { + insinto /usr/lib/shim + newins "${DISTDIR}/shim${ARCHES[$ARCH]}-${PV}.efi.signed" "shim${ARCHES[$ARCH]}.efi.signed" +} diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/shim/files/sbat.csv.in b/sdk_container/src/third_party/coreos-overlay/sys-boot/shim/files/sbat.csv.in new file mode 100644 index 00000000000..43b9f68a7ab --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/shim/files/sbat.csv.in @@ -0,0 +1,3 @@ +sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md +shim,4,UEFI shim,shim,1,https://github.com/rhboot/shim +shim.flatcar,1,Flatcar Container Linux,shim,@@VERSION@@,security@flatcar-linux.org diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/shim/metadata.xml b/sdk_container/src/third_party/coreos-overlay/sys-boot/shim/metadata.xml index 097975e3adc..408e4b227de 100644 --- a/sdk_container/src/third_party/coreos-overlay/sys-boot/shim/metadata.xml +++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/shim/metadata.xml @@ -1,4 +1,8 @@ - + + + cpe:/a:redhat:shim + rhboot/shim + diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/shim/shim-15.8-r1.ebuild b/sdk_container/src/third_party/coreos-overlay/sys-boot/shim/shim-15.8-r1.ebuild index 2e0dd7096ea..10defae63cb 100644 --- a/sdk_container/src/third_party/coreos-overlay/sys-boot/shim/shim-15.8-r1.ebuild +++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/shim/shim-15.8-r1.ebuild @@ -11,7 +11,7 @@ KEYWORDS="amd64 arm64" LICENSE="BSD" SLOT="0" -IUSE="" +IUSE="official" RDEPEND="" # TODO: Would be ideal to depend on sys-boot/gnu-efi package, but @@ -31,6 +31,9 @@ src_compile() { local emake_args=( CROSS_COMPILE="${CHOST}-" ) + + sed -e "s/@@VERSION@@/${PVR}/" "${FILESDIR}"/sbat.csv.in >"${WORKDIR}/sbat.csv" || die + # Apparently our environment already has the ARCH variable in # it, and Makefile picks it up instead of figuring it out # itself with the compiler -dumpmachine flag. But also it @@ -41,8 +44,17 @@ src_compile() { elif use arm64; then emake_args+=( ARCH=aarch64 ) fi - emake_args+=( ENABLE_SBSIGN=1 ) + emake_args+=( ENABLE_SBSIGN=1 ) + emake_args+=( SBATPATH="${WORKDIR}/sbat.csv" ) + + if use official; then + if [ -z "${SHIM_SIGNING_CERTIFICATE}" ]; then + die "use production flag needs env SHIM_SIGNING_CERTIFICATE" + fi + emake_args+=( VENDOR_CERT_FILE="${SHIM_SIGNING_CERTIFICATE}" ) + else emake_args+=( VENDOR_CERT_FILE="/usr/share/sb_keys/shim.der" ) + fi emake "${emake_args[@]}" || die } @@ -55,6 +67,6 @@ src_install() { suffix=aa64 fi insinto /usr/lib/shim - newins "shim${suffix}.efi" 'shim.efi' + newins "shim${suffix}.efi" "shim${suffix}.efi" newins "mm${suffix}.efi" "mm${suffix}.efi" } diff --git a/sdk_container/src/third_party/coreos-overlay/sys-firmware/edk2-aarch64/Manifest b/sdk_container/src/third_party/coreos-overlay/sys-firmware/edk2-aarch64/Manifest deleted file mode 100644 index 22b3138c398..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/sys-firmware/edk2-aarch64/Manifest +++ /dev/null @@ -1 +0,0 @@ -DIST edk2-aarch64-20230524-3.fc38.noarch.rpm 7363923 BLAKE2B 75ff00ea1e988148fbc9a56b8ee3eb44bdec5ceb51b554c3d298191feeb2c876f43740aa3608d3e4b4cc3223aa6bfd8a275f8c6f4c92595af07498b5d6ee68af SHA512 bfe814e0b2230104887a2638f6871fda54cde65937c93226c56cac1a4e1a915b474d690e2862f71ecfc584c3c74d5a091482e038cfc83de9091e5dc49916119b diff --git a/sdk_container/src/third_party/coreos-overlay/sys-firmware/edk2-aarch64/edk2-aarch64-20220221.ebuild b/sdk_container/src/third_party/coreos-overlay/sys-firmware/edk2-aarch64/edk2-aarch64-20220221.ebuild deleted file mode 100644 index d1fead7ff07..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/sys-firmware/edk2-aarch64/edk2-aarch64-20220221.ebuild +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2024 The Flatcar Maintainers. -# Distributed under the terms of the GNU General Public License v2 - -EAPI=8 - -inherit rpm - -DESCRIPTION="Fedora's build of edk2 ARM64 EFI firmware" -HOMEPAGE="https://packages.fedoraproject.org/pkgs/edk2/edk2-aarch64/" -SRC_URI="https://kojipkgs.fedoraproject.org//packages/edk2/20230524/3.fc38/noarch/edk2-aarch64-20230524-3.fc38.noarch.rpm" - -LICENSE="BSD-2-Clause-Patent openssl" -SLOT="0" -KEYWORDS="amd64 arm64" - -S="${WORKDIR}" - -src_install() { - # Avoid collision with qemu installed config file - mv usr/share/qemu/firmware/{60,61}-edk2-aarch64.json - insinto / - doins -r * -} diff --git a/sdk_container/src/third_party/portage-stable/app-crypt/efitools/Manifest b/sdk_container/src/third_party/portage-stable/app-crypt/efitools/Manifest deleted file mode 100644 index aced0dc8f91..00000000000 --- a/sdk_container/src/third_party/portage-stable/app-crypt/efitools/Manifest +++ /dev/null @@ -1 +0,0 @@ -DIST efitools-1.9.2.tar.gz 116037 BLAKE2B b3540932eb112e362fd0eed47090360603807dcaec8c6a10058618f8252eeb5dcbbd703d313cb6fadae62c1312815080cf2c77fc86f9dfc9f9afca24ad97f584 SHA512 77e0ad7e865814ed388ff6daabe0f4b49ba51672bf2cbb98b7905e209cbd28f9ede2f73213ce45af8a978c1e67dba24ec88a1188661317cc22317b47e575cde8 diff --git a/sdk_container/src/third_party/portage-stable/app-crypt/efitools/efitools-1.9.2-r1.ebuild b/sdk_container/src/third_party/portage-stable/app-crypt/efitools/efitools-1.9.2-r1.ebuild deleted file mode 100644 index 0deba136bb4..00000000000 --- a/sdk_container/src/third_party/portage-stable/app-crypt/efitools/efitools-1.9.2-r1.ebuild +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 1999-2023 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=8 - -inherit flag-o-matic toolchain-funcs - -DESCRIPTION="Tools for manipulating UEFI secure boot platforms" -HOMEPAGE="https://git.kernel.org/cgit/linux/kernel/git/jejb/efitools.git" -SRC_URI="https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git/snapshot/${P}.tar.gz" - -LICENSE="GPL-2 LGPL-2.1" -SLOT="0" -KEYWORDS="amd64 ~arm64 x86" -IUSE="static" - -LIB_DEPEND="dev-libs/openssl:=[static-libs(+)]" - -RDEPEND=" - !static? ( ${LIB_DEPEND//\[static-libs(+)]} ) - sys-apps/util-linux" -DEPEND="${RDEPEND} - static? ( ${LIB_DEPEND} ) - sys-boot/gnu-efi" -BDEPEND=" - app-crypt/sbsigntools - dev-perl/File-Slurp - sys-apps/help2man - virtual/pkgconfig" - -PATCHES=( - "${FILESDIR}"/1.9.2-clang16.patch - "${FILESDIR}"/1.9.2-Makefile.patch -) - -src_prepare() { - default - - # Let it build with clang - if tc-is-clang; then - sed -i -e 's/-fno-toplevel-reorder//g' Make.rules || die - fi - - if use static; then - append-ldflags -static - export STATIC_FLAG=--static - fi -} - -src_configure() { - # Calls LD directly, doesn't respect LDFLAGS. Low level package anyway. - # See bug #908813. - filter-lto - - tc-export AR CC LD NM OBJCOPY PKG_CONFIG -} diff --git a/sdk_container/src/third_party/portage-stable/app-crypt/efitools/files/1.9.2-Makefile.patch b/sdk_container/src/third_party/portage-stable/app-crypt/efitools/files/1.9.2-Makefile.patch deleted file mode 100644 index e8e99b1858a..00000000000 --- a/sdk_container/src/third_party/portage-stable/app-crypt/efitools/files/1.9.2-Makefile.patch +++ /dev/null @@ -1,121 +0,0 @@ ---- a/Makefile -+++ b/Makefile -@@ -21,6 +21,8 @@ - KEYBLACKLISTAUTH = $(ALLKEYS:=-blacklist.auth) - KEYHASHBLACKLISTAUTH = $(ALLKEYS:=-hash-blacklist.auth) - -+SSL_LIBS = $(shell $(PKG_CONFIG) $(STATIC_FLAG) --libs libcrypto) -+ - export TOPDIR := $(shell pwd)/ - - include Make.rules -@@ -88,31 +90,31 @@ - ShimReplace.so: lib/lib-efi.a - - cert-to-efi-sig-list: cert-to-efi-sig-list.o lib/lib.a -- $(CC) $(ARCH3264) -o $@ $< lib/lib.a -lcrypto -+ $(CC) $(LDFLAGS) $(ARCH3264) -o $@ $< lib/lib.a $(SSL_LIBS) - - sig-list-to-certs: sig-list-to-certs.o lib/lib.a -- $(CC) $(ARCH3264) -o $@ $< lib/lib.a -lcrypto -+ $(CC) $(LDFLAGS) $(ARCH3264) -o $@ $< lib/lib.a $(SSL_LIBS) - - sign-efi-sig-list: sign-efi-sig-list.o lib/lib.a -- $(CC) $(ARCH3264) -o $@ $< lib/lib.a -lcrypto -+ $(CC) $(LDFLAGS) $(ARCH3264) -o $@ $< lib/lib.a $(SSL_LIBS) - - hash-to-efi-sig-list: hash-to-efi-sig-list.o lib/lib.a -- $(CC) $(ARCH3264) -o $@ $< lib/lib.a -+ $(CC) $(LDFLAGS) $(ARCH3264) -o $@ $< lib/lib.a - - cert-to-efi-hash-list: cert-to-efi-hash-list.o lib/lib.a -- $(CC) $(ARCH3264) -o $@ $< lib/lib.a -lcrypto -+ $(CC) $(LDFLAGS) $(ARCH3264) -o $@ $< lib/lib.a $(SSL_LIBS) - - efi-keytool: efi-keytool.o lib/lib.a -- $(CC) $(ARCH3264) -o $@ $< lib/lib.a -+ $(CC) $(LDFLAGS) $(ARCH3264) -o $@ $< lib/lib.a - - efi-readvar: efi-readvar.o lib/lib.a -- $(CC) $(ARCH3264) -o $@ $< lib/lib.a -lcrypto -+ $(CC) $(LDFLAGS) $(ARCH3264) -o $@ $< lib/lib.a $(SSL_LIBS) - - efi-updatevar: efi-updatevar.o lib/lib.a -- $(CC) $(ARCH3264) -o $@ $< lib/lib.a -lcrypto -+ $(CC) $(LDFLAGS) $(ARCH3264) -o $@ $< lib/lib.a $(SSL_LIBS) - - flash-var: flash-var.o lib/lib.a -- $(CC) $(ARCH3264) -o $@ $< lib/lib.a -+ $(CC) $(LDFLAGS) $(ARCH3264) -o $@ $< lib/lib.a - - clean: - rm -f PK.* KEK.* DB.* $(EFIFILES) $(EFISIGNED) $(BINARIES) *.o *.so ---- a/Make.rules -+++ b/Make.rules -@@ -15,8 +15,7 @@ - endif - INCDIR = -I$(TOPDIR)include/ -I/usr/include/efi -I/usr/include/efi/$(ARCH) -I/usr/include/efi/protocol - CPPFLAGS = -DCONFIG_$(ARCH) --CFLAGS = -O2 -g $(ARCH3264) -fpic -Wall -fshort-wchar -fno-strict-aliasing -fno-merge-constants -fno-stack-protector -ffreestanding -fno-stack-check --LDFLAGS = -nostdlib -+CFLAGS += $(ARCH3264) -fpic -Wall -fshort-wchar -fno-strict-aliasing -fno-merge-constants -fno-stack-protector -ffreestanding -fno-stack-check - CRTOBJ = crt0-efi-$(ARCH).o - CRTPATHS = /lib /lib64 /lib/efi /lib64/efi /usr/lib /usr/lib64 /usr/lib/efi /usr/lib64/efi /usr/lib/gnuefi /usr/lib64/gnuefi - CRTPATH = $(shell for f in $(CRTPATHS); do if [ -e $$f/$(CRTOBJ) ]; then echo $$f; break; fi; done) -@@ -24,10 +23,9 @@ - # there's a bug in the gnu tools ... the .reloc section has to be - # aligned otherwise the file alignment gets screwed up - LDSCRIPT = elf_$(ARCH)_efi.lds --LDFLAGS += -shared -Bsymbolic $(CRTOBJS) -L $(CRTPATH) -L /usr/lib -L /usr/lib64 -T $(LDSCRIPT) -+LIBS += -nostdlib -shared -Bsymbolic $(CRTOBJS) -L $(CRTPATH) -T $(LDSCRIPT) - LOADLIBES = -lefi -lgnuefi $(shell $(CC) $(ARCH3264) -print-libgcc-file-name) - FORMAT = --target=efi-app-$(ARCH) --OBJCOPY = objcopy - MYGUID = 11111111-2222-3333-4444-123456789abc - INSTALL = install - BINDIR = $(DESTDIR)/usr/bin -@@ -47,12 +45,12 @@ - endif - - ifeq ($(ARCH),arm) -- LDFLAGS += --defsym=EFI_SUBSYSTEM=0x0a -+ LIBS += --defsym=EFI_SUBSYSTEM=0x0a - FORMAT = -O binary - endif - - ifeq ($(ARCH),aarch64) -- LDFLAGS += --defsym=EFI_SUBSYSTEM=0x0a -+ LIBS += --defsym=EFI_SUBSYSTEM=0x0a - FORMAT = -O binary - endif - -@@ -61,9 +59,9 @@ - -j .rel -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ - -j .reloc $(FORMAT) $*.so $@ - %.so: %.o -- $(LD) $(LDFLAGS) $^ -o $@ $(LOADLIBES) -+ $(LD) $(LIBS) $^ -o $@ $(LOADLIBES) - # check we have no undefined symbols -- nm -D $@ | grep ' U ' && exit 1 || exit 0 -+ $(NM) -D $@ | grep ' U ' && exit 1 || exit 0 - - %.h: %.auth - ./xxdi.pl $< > $@ -@@ -71,7 +69,7 @@ - %.hash: %.efi hash-to-efi-sig-list - ./hash-to-efi-sig-list $< $@ - --%-blacklist.esl: %.crt cert-to-efi-hash-list -+%-blacklist.esl: %.crt cert-to-efi-sig-list - ./cert-to-efi-sig-list $< $@ - - %-hash-blacklist.esl: %.crt cert-to-efi-hash-list -@@ -129,7 +127,7 @@ - # sbsign --key KEK.key --cert KEK.crt --output $@ $< - - %.a: -- ar rcv $@ $^ -+ $(AR) rcv $@ $^ - - doc/%.1: doc/%.1.in % - $(HELP2MAN) --no-info -i $< -o $@ ./$* diff --git a/sdk_container/src/third_party/portage-stable/app-crypt/efitools/files/1.9.2-clang16.patch b/sdk_container/src/third_party/portage-stable/app-crypt/efitools/files/1.9.2-clang16.patch deleted file mode 100644 index 944a731bcde..00000000000 --- a/sdk_container/src/third_party/portage-stable/app-crypt/efitools/files/1.9.2-clang16.patch +++ /dev/null @@ -1,108 +0,0 @@ ---- a/cert-to-efi-sig-list.c -+++ b/cert-to-efi-sig-list.c -@@ -6,7 +6,6 @@ - - - #include --#define __STDC_VERSION__ 199901L - #include - #ifdef CONFIG_arm - /* FIXME: ---- a/efi-keytool.c -+++ b/efi-keytool.c -@@ -15,7 +15,6 @@ - #include - #include - --#define __STDC_VERSION__ 199901L - #include - - #include ---- a/efi-readvar.c -+++ b/efi-readvar.c -@@ -17,7 +17,6 @@ - - #include - --#define __STDC_VERSION__ 199901L - #include - - #include ---- a/efi-updatevar.c -+++ b/efi-updatevar.c -@@ -20,7 +20,6 @@ - #include - #include - --#define __STDC_VERSION__ 199901L - #include - - #include ---- a/flash-var.c -+++ b/flash-var.c -@@ -1,3 +1,5 @@ -+#define _XOPEN_SOURCE 700 -+ - #include - #include - #include -@@ -10,7 +12,6 @@ - #include - #include - --#define __STDC_VERSION__ 199901L - #include - - #include ---- a/hash-to-efi-sig-list.c -+++ b/hash-to-efi-sig-list.c -@@ -4,7 +4,6 @@ - * see COPYING file - */ - #include --#define __STDC_VERSION__ 199901L - #include - #ifdef CONFIG_arm - /* FIXME: ---- a/include/variableformat.h -+++ b/include/variableformat.h -@@ -109,7 +109,7 @@ - - #pragma pack() - --inline BOOLEAN -+static inline BOOLEAN - IsValidVariableHeader (VARIABLE_HEADER *vh) { - if (vh == NULL || vh->StartId != VARIABLE_DATA) - return FALSE; ---- a/lib/kernel_efivars.c -+++ b/lib/kernel_efivars.c -@@ -16,7 +16,6 @@ - #include - #include - --#define __STDC_VERSION__ 199901L - #include - - #include ---- a/sig-list-to-certs.c -+++ b/sig-list-to-certs.c -@@ -4,7 +4,6 @@ - * see COPYING file - */ - #include --#define __STDC_VERSION__ 199901L - #include - #ifdef CONFIG_arm - /* FIXME: ---- a/sign-efi-sig-list.c -+++ b/sign-efi-sig-list.c -@@ -4,7 +4,7 @@ - * see COPYING file - */ - #include --#define __STDC_VERSION__ 199901L -+#define _XOPEN_SOURCE 700 - #include - #ifdef CONFIG_arm - /* FIXME: diff --git a/sdk_container/src/third_party/portage-stable/app-crypt/p11-kit/Manifest b/sdk_container/src/third_party/portage-stable/app-crypt/p11-kit/Manifest new file mode 100644 index 00000000000..851345f5f63 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/app-crypt/p11-kit/Manifest @@ -0,0 +1,2 @@ +DIST p11-kit-0.25.3.tar.xz 991528 BLAKE2B 5c695c1ef95edf4bbbab001aa634076c433df0bc89cb8104deaec2ce00c6908640e467755b49c6900e5d7d5d81e1a3871f4978a212c6f6ae088386ac0b95289a SHA512 ad2d393bf122526cbba18dc9d5a13f2c1cad7d70125ec90ffd02059dfa5ef30ac59dfc0bb9bc6380c8f317e207c9e87e895f1945634f56ddf910c2958868fb4c +DIST p11-kit-0.25.5.tar.xz 1002056 BLAKE2B 96d6a9c2807586abafae4da4df89f566672733963997d6a83e00aaf83a7a0c0e2995638f505e98fb87a90c60bde28814f1e8b7d5071bf0af96bb0467105a1ddc SHA512 177ec6ff5eb891901078306dce2bf3f5c1a0e5c2a8c493bdf5a08ae1ff1240fdf6952961e973c373f80ac3d1d5a9927e07f4da49e4ff92269d992e744889fc94 diff --git a/sdk_container/src/third_party/portage-stable/app-crypt/p11-kit/files/p11-kit-0.25.3-pointer.patch b/sdk_container/src/third_party/portage-stable/app-crypt/p11-kit/files/p11-kit-0.25.3-pointer.patch new file mode 100644 index 00000000000..9b316ee2fad --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/app-crypt/p11-kit/files/p11-kit-0.25.3-pointer.patch @@ -0,0 +1,109 @@ +https://bugs.gentoo.org/918982 +https://github.com/p11-glue/p11-kit/commit/d49c92c8420db6ee4c88515bdb014f68f4d471d9 + +From d49c92c8420db6ee4c88515bdb014f68f4d471d9 Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Sat, 2 Dec 2023 09:24:01 +0900 +Subject: [PATCH] import-object: Avoid integer truncation on 32-bit platforms +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The build fails when compiling for 32-bit platforms with +-Werror=incompatible-pointer-types: + + CFLAGS="-m32 -march=i686 -Werror=incompatible-pointer-types -Werror=implicit -Werror=int-conversion" setarch i686 -- meson setup _build + setarch i686 -- meson compile -C _build -v + ... + + ../p11-kit/import-object.c: In function ‘add_attrs_pubkey_rsa’: + ../p11-kit/import-object.c:223:62: error: passing argument 3 of ‘p11_asn1_read’ from incompatible pointer type [-Werror=incompatible-pointer-types] + 223 | attr_modulus.pValue = p11_asn1_read (asn, "modulus", &attr_modulus.ulValueLen); + | ^~~~~~~~~~~~~~~~~~~~~~~~ + | | + | long unsigned int * + +Reported by Sam James in: +https://github.com/p11-glue/p11-kit/issues/608 + +Signed-off-by: Daiki Ueno +--- + p11-kit/import-object.c | 30 +++++++++++++++++++++++++++--- + 1 file changed, 27 insertions(+), 3 deletions(-) + +diff --git a/p11-kit/import-object.c b/p11-kit/import-object.c +index feee0765..fb47b964 100644 +--- a/p11-kit/import-object.c ++++ b/p11-kit/import-object.c +@@ -55,6 +55,7 @@ + #endif + + #include ++#include + #include + #include + #include +@@ -201,6 +202,7 @@ add_attrs_pubkey_rsa (CK_ATTRIBUTE *attrs, + CK_ATTRIBUTE attr_encrypt = { CKA_ENCRYPT, &tval, sizeof (tval) }; + CK_ATTRIBUTE attr_modulus = { CKA_MODULUS, }; + CK_ATTRIBUTE attr_exponent = { CKA_PUBLIC_EXPONENT, }; ++ size_t len = 0; + + pubkey = p11_asn1_read (info, "subjectPublicKey", &pubkey_len); + if (pubkey == NULL) { +@@ -220,17 +222,31 @@ add_attrs_pubkey_rsa (CK_ATTRIBUTE *attrs, + goto cleanup; + } + +- attr_modulus.pValue = p11_asn1_read (asn, "modulus", &attr_modulus.ulValueLen); ++ attr_modulus.pValue = p11_asn1_read (asn, "modulus", &len); + if (attr_modulus.pValue == NULL) { + p11_message (_("failed to obtain modulus")); + goto cleanup; + } ++#if ULONG_MAX < SIZE_MAX ++ if (len > ULONG_MAX) { ++ p11_message (_("failed to obtain modulus")); ++ goto cleanup; ++ } ++#endif ++ attr_modulus.ulValueLen = len; + +- attr_exponent.pValue = p11_asn1_read (asn, "publicExponent", &attr_exponent.ulValueLen); ++ attr_exponent.pValue = p11_asn1_read (asn, "publicExponent", &len); + if (attr_exponent.pValue == NULL) { + p11_message (_("failed to obtain exponent")); + goto cleanup; + } ++#if ULONG_MAX < SIZE_MAX ++ if (len > ULONG_MAX) { ++ p11_message (_("failed to obtain exponent")); ++ goto cleanup; ++ } ++#endif ++ attr_exponent.ulValueLen = len; + + result = p11_attrs_build (attrs, &attr_key_type, &attr_encrypt, &attr_modulus, &attr_exponent, NULL); + if (result == NULL) { +@@ -260,12 +276,20 @@ add_attrs_pubkey_ec (CK_ATTRIBUTE *attrs, + CK_ATTRIBUTE attr_key_type = { CKA_KEY_TYPE, &key_type, sizeof (key_type) }; + CK_ATTRIBUTE attr_ec_params = { CKA_EC_PARAMS, }; + CK_ATTRIBUTE attr_ec_point = { CKA_EC_POINT, }; ++ size_t len = 0; + +- attr_ec_params.pValue = p11_asn1_read (info, "algorithm.parameters", &attr_ec_params.ulValueLen); ++ attr_ec_params.pValue = p11_asn1_read (info, "algorithm.parameters", &len); + if (attr_ec_params.pValue == NULL) { + p11_message (_("failed to obtain EC parameters")); + goto cleanup; + } ++#if ULONG_MAX < SIZE_MAX ++ if (len > ULONG_MAX) { ++ p11_message (_("failed to obtain EC parameters")); ++ goto cleanup; ++ } ++#endif ++ attr_ec_params.ulValueLen = len; + + /* subjectPublicKey is read as BIT STRING value which contains + * EC point data. We need to DER encode this data as OCTET STRING. diff --git a/sdk_container/src/third_party/portage-stable/app-crypt/efitools/metadata.xml b/sdk_container/src/third_party/portage-stable/app-crypt/p11-kit/metadata.xml similarity index 67% rename from sdk_container/src/third_party/portage-stable/app-crypt/efitools/metadata.xml rename to sdk_container/src/third_party/portage-stable/app-crypt/p11-kit/metadata.xml index 115e9d64a66..91df1af79aa 100644 --- a/sdk_container/src/third_party/portage-stable/app-crypt/efitools/metadata.xml +++ b/sdk_container/src/third_party/portage-stable/app-crypt/p11-kit/metadata.xml @@ -2,4 +2,7 @@ + + p11-glue/p11-kit + diff --git a/sdk_container/src/third_party/portage-stable/app-crypt/p11-kit/p11-kit-0.25.3-r2.ebuild b/sdk_container/src/third_party/portage-stable/app-crypt/p11-kit/p11-kit-0.25.3-r2.ebuild new file mode 100644 index 00000000000..f27bbaf48cf --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/app-crypt/p11-kit/p11-kit-0.25.3-r2.ebuild @@ -0,0 +1,77 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +PYTHON_COMPAT=( python3_{10..13} ) +inherit bash-completion-r1 meson-multilib python-any-r1 + +DESCRIPTION="Provides a standard configuration setup for installing PKCS#11" +HOMEPAGE="https://p11-glue.github.io/p11-glue/p11-kit.html" +SRC_URI="https://github.com/p11-glue/p11-kit/releases/download/${PV}/${P}.tar.xz" + +LICENSE="MIT" +SLOT="0" +KEYWORDS="~alpha amd64 arm arm64 hppa ~loong ~m68k ~mips ppc ppc64 ~riscv ~s390 sparc x86 ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x64-solaris" +IUSE="+libffi gtk-doc nls systemd test" +RESTRICT="!test? ( test )" + +RDEPEND=" + app-misc/ca-certificates + >=dev-libs/libtasn1-3.4:=[${MULTILIB_USEDEP}] + libffi? ( dev-libs/libffi:=[${MULTILIB_USEDEP}] ) + systemd? ( sys-apps/systemd:= ) +" +DEPEND="${RDEPEND}" +BDEPEND=" + ${PYTHON_DEPS} + app-text/docbook-xsl-stylesheets + dev-libs/libxslt + virtual/pkgconfig + gtk-doc? ( dev-util/gtk-doc ) + nls? ( sys-devel/gettext ) +" + +PATCHES=( + "${FILESDIR}"/p11-kit-0.25.3-pointer.patch +) + +src_prepare() { + default + + # Relies on dlopen which won't work for multilib tests (bug #913971) + cat <<-EOF > "${S}"/p11-kit/test-server.sh || die + #!/bin/sh + exit 77 + EOF +} + +multilib_src_configure() { + # Disable unsafe tests, bug#502088 + export FAKED_MODE=1 + + local native_file="${T}"/meson.${CHOST}.${ABI}.ini.local + + # p11-kit doesn't need this to build and castxml needs Clang. To get + # a deterministic non-automagic build, always disable the search for + # castxml. + cat >> ${native_file} <<-EOF || die + [binaries] + castxml='castxml-falseified' + EOF + + local emesonargs=( + --native-file "${native_file}" + -Dbashcompdir="$(get_bashcompdir)" + -Dtrust_module=enabled + -Dtrust_paths="${EPREFIX}"/etc/ssl/certs/ca-certificates.crt + $(meson_feature libffi) + $(meson_use nls) + $(meson_use test) + $(meson_native_use_bool gtk-doc gtk_doc) + $(meson_native_true man) + $(meson_native_use_feature systemd) + ) + + meson_src_configure +} diff --git a/sdk_container/src/third_party/portage-stable/app-crypt/p11-kit/p11-kit-0.25.5.ebuild b/sdk_container/src/third_party/portage-stable/app-crypt/p11-kit/p11-kit-0.25.5.ebuild new file mode 100644 index 00000000000..0c23a73251f --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/app-crypt/p11-kit/p11-kit-0.25.5.ebuild @@ -0,0 +1,73 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +PYTHON_COMPAT=( python3_{10..13} ) +inherit bash-completion-r1 meson-multilib python-any-r1 + +DESCRIPTION="Provides a standard configuration setup for installing PKCS#11" +HOMEPAGE="https://p11-glue.github.io/p11-glue/p11-kit.html" +SRC_URI="https://github.com/p11-glue/p11-kit/releases/download/${PV}/${P}.tar.xz" + +LICENSE="MIT" +SLOT="0" +KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~loong ~m68k ~mips ~ppc ~ppc64 ~riscv ~s390 ~sparc ~x86 ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x64-solaris" +IUSE="+libffi gtk-doc nls systemd test" +RESTRICT="!test? ( test )" + +RDEPEND=" + app-misc/ca-certificates + >=dev-libs/libtasn1-3.4:=[${MULTILIB_USEDEP}] + libffi? ( dev-libs/libffi:=[${MULTILIB_USEDEP}] ) + systemd? ( sys-apps/systemd:= ) +" +DEPEND="${RDEPEND}" +BDEPEND=" + ${PYTHON_DEPS} + app-text/docbook-xsl-stylesheets + dev-libs/libxslt + virtual/pkgconfig + gtk-doc? ( dev-util/gtk-doc ) + nls? ( sys-devel/gettext ) +" + +src_prepare() { + default + + # Relies on dlopen which won't work for multilib tests (bug #913971) + cat <<-EOF > "${S}"/p11-kit/test-server.sh || die + #!/bin/sh + exit 77 + EOF +} + +multilib_src_configure() { + # Disable unsafe tests, bug#502088 + export FAKED_MODE=1 + + local native_file="${T}"/meson.${CHOST}.${ABI}.ini.local + + # p11-kit doesn't need this to build and castxml needs Clang. To get + # a deterministic non-automagic build, always disable the search for + # castxml. + cat >> ${native_file} <<-EOF || die + [binaries] + castxml='castxml-falseified' + EOF + + local emesonargs=( + --native-file "${native_file}" + -Dbashcompdir="$(get_bashcompdir)" + -Dtrust_module=enabled + -Dtrust_paths="${EPREFIX}"/etc/ssl/certs/ca-certificates.crt + $(meson_feature libffi) + $(meson_use nls) + $(meson_use test) + $(meson_native_use_bool gtk-doc gtk_doc) + $(meson_native_true man) + $(meson_native_use_feature systemd) + ) + + meson_src_configure +} diff --git a/sdk_container/src/third_party/portage-stable/app-emulation/virt-firmware/Manifest b/sdk_container/src/third_party/portage-stable/app-emulation/virt-firmware/Manifest new file mode 100644 index 00000000000..6b3b4e5e76c --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/app-emulation/virt-firmware/Manifest @@ -0,0 +1,2 @@ +DIST virt-firmware-24.4.tar.gz 111964 BLAKE2B 16005a6f911abf227988abaedd45237d44d403f367abd3c2d413f899a6c3e7db2a62edcd36b7408263f101a0f0a20bbea83bf51f7f798077311b478dfc6c9fc1 SHA512 3b13df25177fe5c20e460e2d82453e23ae96cb657f1228ff1c061db4c4197eba719a4d7f51a90fec60a4de2da9a0e9d3f056d53011bd4f61df7f40b706911a1d +DIST virt_firmware-24.7.tar.gz 114229 BLAKE2B a5b6bf39a72ce68622bbc4f75505633b92c322e4a02ab0384bb3b618abfbeeb19cfb057b5333ae53042732b131dcaa475c2c920922c920b0d0c21ef4185ad5b9 SHA512 1cd209b500e0ec1a5b8284b72b499bd16e998fd9489db6c8f8e3b49befb6186c5c09c95b2761254696b479daff1afaf2bdccb6ca7e115b11eb9a5df847f43628 diff --git a/sdk_container/src/third_party/portage-stable/app-emulation/virt-firmware/files/kernel-bootcfg-boot-successful b/sdk_container/src/third_party/portage-stable/app-emulation/virt-firmware/files/kernel-bootcfg-boot-successful new file mode 100644 index 00000000000..5c7ef1a79cc --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/app-emulation/virt-firmware/files/kernel-bootcfg-boot-successful @@ -0,0 +1,9 @@ +#!/sbin/openrc-run +# Copyright 2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +description="UKI Successful Boot" + +start() { + kernel-bootcfg --boot-successful --update-csv || return 1 +} diff --git a/sdk_container/src/third_party/portage-stable/app-emulation/virt-firmware/metadata.xml b/sdk_container/src/third_party/portage-stable/app-emulation/virt-firmware/metadata.xml new file mode 100644 index 00000000000..1059efa31d7 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/app-emulation/virt-firmware/metadata.xml @@ -0,0 +1,19 @@ + + + + + andrewammerlaan@gentoo.org + Andrew Ammerlaan + + + + This is a small collection of tools for edk2 firmware images. They + support decoding and printing the content of firmware volumes. + Variable stores (OVMF_VARS.fd) can be modified, for example to enroll + secure boot certificates. + + + virt-firmware + kraxel/virt-firmware + + diff --git a/sdk_container/src/third_party/portage-stable/app-emulation/virt-firmware/virt-firmware-24.4.ebuild b/sdk_container/src/third_party/portage-stable/app-emulation/virt-firmware/virt-firmware-24.4.ebuild new file mode 100644 index 00000000000..36b536044e1 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/app-emulation/virt-firmware/virt-firmware-24.4.ebuild @@ -0,0 +1,52 @@ +# Copyright 2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +PYTHON_COMPAT=( python3_{10..12} ) +DISTUTILS_USE_PEP517=setuptools +PYPI_NO_NORMALIZE=1 + +inherit distutils-r1 optfeature pypi systemd + +DESCRIPTION="Tools for ovmf/armvirt firmware volumes" +HOMEPAGE=" + https://gitlab.com/kraxel/virt-firmware + https://pypi.org/project/virt-firmware/ +" + +LICENSE="GPL-2" +SLOT="0" +KEYWORDS="~amd64 ~arm ~arm64 ~x86" + +# Currently requires files in /boot and read/write to efivars +RESTRICT="test" + +RDEPEND=" + dev-python/cryptography[${PYTHON_USEDEP}] + dev-python/pefile[${PYTHON_USEDEP}] +" + +distutils_enable_tests unittest + +python_test() { + eunittest tests +} + +python_install_all() { + distutils-r1_python_install_all + + doman man/*.1 + + doinitd "${FILESDIR}/kernel-bootcfg-boot-successful" + systemd_dounit systemd/kernel-bootcfg-boot-successful.service + + # Use our own provided by sys-kernel/installkernel[efistub,systemd] + #exeinto /usr/lib/kernel/install.d + #doexe systemd/99-uki-uefi-setup.install +} + +pkg_postinst() { + optfeature "automatically updating UEFI configuration on each kernel installation or removal" \ + "sys-kernel/installkernel[systemd,efistub]" +} diff --git a/sdk_container/src/third_party/portage-stable/app-emulation/virt-firmware/virt-firmware-24.7.ebuild b/sdk_container/src/third_party/portage-stable/app-emulation/virt-firmware/virt-firmware-24.7.ebuild new file mode 100644 index 00000000000..33bca1b06d1 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/app-emulation/virt-firmware/virt-firmware-24.7.ebuild @@ -0,0 +1,55 @@ +# Copyright 2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +PYTHON_COMPAT=( python3_{10..12} ) +DISTUTILS_USE_PEP517=setuptools + +inherit distutils-r1 optfeature pypi systemd + +DESCRIPTION="Tools for ovmf/armvirt firmware volumes" +HOMEPAGE=" + https://gitlab.com/kraxel/virt-firmware + https://pypi.org/project/virt-firmware/ +" + +LICENSE="GPL-2" +SLOT="0" +KEYWORDS="~amd64 ~arm ~arm64 ~x86" + +RDEPEND=" + dev-python/cryptography[${PYTHON_USEDEP}] + dev-python/pefile[${PYTHON_USEDEP}] +" + +# Need systemd-detect-virt +BDEPEND=" + test? ( + sys-apps/systemd + ) +" + +distutils_enable_tests unittest + +python_test() { + eunittest tests +} + +python_install_all() { + distutils-r1_python_install_all + + doman man/*.1 + + doinitd "${FILESDIR}/kernel-bootcfg-boot-successful" + systemd_dounit systemd/kernel-bootcfg-boot-successful.service + + # Use our own provided by sys-kernel/installkernel[efistub,systemd] + #exeinto /usr/lib/kernel/install.d + #doexe systemd/99-uki-uefi-setup.install +} + +pkg_postinst() { + optfeature "automatically updating UEFI configuration on each kernel installation or removal" \ + "sys-kernel/installkernel[systemd,efistub]" +} diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-core/Manifest b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-core/Manifest new file mode 100644 index 00000000000..9beb745f780 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-core/Manifest @@ -0,0 +1 @@ +DIST azure-sdk-for-cpp-1289063cc2a7ba01fa7a8c7cd92155ef401c4cba.tar.gz 3130906 BLAKE2B 8fab2710f9c8bc5eb69b5f6bc389cf00cfaba1c6902ffa9a9e67e96bd91e508a9b1c643e57fbe74c68fa840bc707e00672ca0e3979baaabefb021849bb5815bb SHA512 19d122bd153ababd90d238a94b8227e56c17a677dc478fd680c099856fc874367a4c8aa83ccf372139400772951dad69899471970ac18088f901d67047b7755f diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-core/azure-core-1.14.0.ebuild b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-core/azure-core-1.14.0.ebuild new file mode 100644 index 00000000000..1fdf31d0c26 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-core/azure-core-1.14.0.ebuild @@ -0,0 +1,52 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit cmake + +COMMIT="1289063cc2a7ba01fa7a8c7cd92155ef401c4cba" +MY_P="azure-sdk-for-cpp-${COMMIT}" +DESCRIPTION="Azure SDK for C++" +HOMEPAGE="https://azure.github.io/azure-sdk-for-cpp/" +SRC_URI="https://github.com/Azure/azure-sdk-for-cpp/archive/${COMMIT}.tar.gz -> ${MY_P}.tar.gz" +S="${WORKDIR}/${MY_P}/sdk/core/${PN}" +LICENSE="MIT" +SLOT="0/${PV}" +KEYWORDS="~amd64" +IUSE="doc" +RESTRICT="test" # Too many online tests. + +RDEPEND=" + dev-libs/openssl:= + net-misc/curl[ssl] +" +DEPEND=" + ${RDEPEND} +" +BDEPEND=" + virtual/pkgconfig + doc? ( app-text/doxygen ) +" + +src_prepare() { + cmake_src_prepare + cd ../../.. || die + eapply "${FILESDIR}"/azure-sdk-for-cpp-soversion.patch +} + +src_configure() { + local mycmakeargs=( + -DBUILD_DOCUMENTATION=$(usex doc) + -DWARNINGS_AS_ERRORS=no + ) + + AZURE_SDK_DISABLE_AUTO_VCPKG=yes \ + cmake_src_configure +} + +src_install() { + cmake_src_install + rm -v "${ED}"/usr/share/*/copyright || die + use doc && dodoc -r "${BUILD_DIR}"/docs/html +} diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-core/files/azure-sdk-for-cpp-soversion.patch b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-core/files/azure-sdk-for-cpp-soversion.patch new file mode 100644 index 00000000000..550f9f22847 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-core/files/azure-sdk-for-cpp-soversion.patch @@ -0,0 +1,216 @@ +diff --git a/sdk/attestation/azure-security-attestation/CMakeLists.txt b/sdk/attestation/azure-security-attestation/CMakeLists.txt +index 8dec8cf..dff3461 100644 +--- a/sdk/attestation/azure-security-attestation/CMakeLists.txt ++++ b/sdk/attestation/azure-security-attestation/CMakeLists.txt +@@ -86,6 +86,7 @@ create_code_coverage(attestation azure-security-attestation azure-security-attes + + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-attestation PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-attestation ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/core/azure-core-amqp/CMakeLists.txt b/sdk/core/azure-core-amqp/CMakeLists.txt +index 3ef7bf8..e99d57f 100644 +--- a/sdk/core/azure-core-amqp/CMakeLists.txt ++++ b/sdk/core/azure-core-amqp/CMakeLists.txt +@@ -177,6 +177,7 @@ target_link_libraries(azure-core-amqp PRIVATE + PUBLIC Azure::azure-core) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-core-amqp PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-core-amqp ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt b/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt +index 23cf7d1..3834d6c 100644 +--- a/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt ++++ b/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt +@@ -80,6 +80,7 @@ if (BUILD_AZURE_CORE_TRACING_OPENTELEMETRY) + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-core-tracing-opentelemetry PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-core-tracing-opentelemetry ${AZ_LIBRARY_VERSION}) + + if(BUILD_AZURE_CORE_TRACING_OPENTELEMETRY) +diff --git a/sdk/core/azure-core/CMakeLists.txt b/sdk/core/azure-core/CMakeLists.txt +index 87c5cfd..9dbf5a0 100644 +--- a/sdk/core/azure-core/CMakeLists.txt ++++ b/sdk/core/azure-core/CMakeLists.txt +@@ -192,6 +192,7 @@ if(BUILD_TRANSPORT_WINHTTP) + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-core PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-core ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt +index 2152690..4af757c 100644 +--- a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt ++++ b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt +@@ -91,6 +91,7 @@ target_link_libraries(azure-messaging-eventhubs-checkpointstore-blob + create_code_coverage(eventhubs azure-messaging-eventhubs-checkpointstore-blob azure-messaging-eventhubs-blobcheckpointstore-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-messaging-eventhubs-checkpointstore-blob PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + #generate_documentation(azure-messaging-eventhubs-checkpointstore-blob ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-messaging-eventhubs-checkpointstore-blob ${AZ_LIBRARY_VERSION}) + +diff --git a/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt b/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt +index 0ea0b8e..e0dbe51 100644 +--- a/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt ++++ b/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt +@@ -116,6 +116,7 @@ target_compile_definitions(azure-messaging-eventhubs PRIVATE _azure_BUILDING_SDK + create_code_coverage(eventhubs azure-messaging-eventhubs azure-messaging-eventhubs-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-messaging-eventhubs PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-messaging-eventhubs ${AZ_LIBRARY_VERSION}) + + add_subdirectory(test) +diff --git a/sdk/identity/azure-identity/CMakeLists.txt b/sdk/identity/azure-identity/CMakeLists.txt +index 57fe6bb..3c21177 100644 +--- a/sdk/identity/azure-identity/CMakeLists.txt ++++ b/sdk/identity/azure-identity/CMakeLists.txt +@@ -117,6 +117,7 @@ else() + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-identity PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-identity ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt +index 5f70eb3..b065d33 100644 +--- a/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt +@@ -95,6 +95,7 @@ target_compile_definitions(azure-security-keyvault-administration PRIVATE _azure + create_code_coverage(keyvault azure-security-keyvault-administration azure-security-keyvault-administration-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-administration PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-administration ${AZ_LIBRARY_VERSION}) + if(BUILD_TESTING) + +diff --git a/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt +index 0806e09..8014038 100644 +--- a/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt +@@ -100,6 +100,7 @@ target_compile_definitions(azure-security-keyvault-certificates PRIVATE _azure_B + create_code_coverage(keyvault azure-security-keyvault-certificates azure-security-keyvault-certificates-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-certificates PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-certificates ${AZ_LIBRARY_VERSION}) + + if(BUILD_TESTING) +diff --git a/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt +index 6217fd1..2de5e64 100644 +--- a/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt +@@ -138,6 +138,7 @@ target_compile_definitions(azure-security-keyvault-keys PRIVATE _azure_BUILDING_ + create_code_coverage(keyvault azure-security-keyvault-keys azure-security-keyvault-keys-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-keys PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-keys ${AZ_LIBRARY_VERSION}) + + if(BUILD_TESTING) +diff --git a/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt +index 7cc62a8..3664d8c 100644 +--- a/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt +@@ -115,6 +115,7 @@ target_compile_definitions(azure-security-keyvault-secrets PRIVATE _azure_BUILDI + create_code_coverage(keyvault azure-security-keyvault-secrets azure-security-keyvault-secrets-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-secrets PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-secrets ${AZ_LIBRARY_VERSION}) + if(BUILD_TESTING) + +diff --git a/sdk/storage/azure-storage-blobs/CMakeLists.txt b/sdk/storage/azure-storage-blobs/CMakeLists.txt +index f87ceae..657ef33 100644 +--- a/sdk/storage/azure-storage-blobs/CMakeLists.txt ++++ b/sdk/storage/azure-storage-blobs/CMakeLists.txt +@@ -96,6 +96,7 @@ target_link_libraries(azure-storage-blobs PUBLIC Azure::azure-storage-common) + target_compile_definitions(azure-storage-blobs PRIVATE _azure_BUILDING_SDK) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-blobs PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-blobs ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-common/CMakeLists.txt b/sdk/storage/azure-storage-common/CMakeLists.txt +index 30f056d..ce90e8a 100644 +--- a/sdk/storage/azure-storage-common/CMakeLists.txt ++++ b/sdk/storage/azure-storage-common/CMakeLists.txt +@@ -107,6 +107,7 @@ else() + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-common PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-common ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-files-datalake/CMakeLists.txt b/sdk/storage/azure-storage-files-datalake/CMakeLists.txt +index 71905c8..ac82507 100644 +--- a/sdk/storage/azure-storage-files-datalake/CMakeLists.txt ++++ b/sdk/storage/azure-storage-files-datalake/CMakeLists.txt +@@ -92,6 +92,7 @@ target_include_directories( + target_link_libraries(azure-storage-files-datalake PUBLIC Azure::azure-storage-blobs) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-files-datalake PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-files-datalake ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-files-shares/CMakeLists.txt b/sdk/storage/azure-storage-files-shares/CMakeLists.txt +index 891f954..cf6cd92 100644 +--- a/sdk/storage/azure-storage-files-shares/CMakeLists.txt ++++ b/sdk/storage/azure-storage-files-shares/CMakeLists.txt +@@ -88,6 +88,7 @@ target_include_directories( + target_link_libraries(azure-storage-files-shares PUBLIC Azure::azure-storage-common) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-files-shares PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-files-shares ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-queues/CMakeLists.txt b/sdk/storage/azure-storage-queues/CMakeLists.txt +index e567623..2e340d5 100644 +--- a/sdk/storage/azure-storage-queues/CMakeLists.txt ++++ b/sdk/storage/azure-storage-queues/CMakeLists.txt +@@ -81,6 +81,7 @@ target_include_directories( + target_link_libraries(azure-storage-queues PUBLIC Azure::azure-storage-common) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-queues PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-queues ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/tables/azure-data-tables/CMakeLists.txt b/sdk/tables/azure-data-tables/CMakeLists.txt +index 038e267..d7e7976 100644 +--- a/sdk/tables/azure-data-tables/CMakeLists.txt ++++ b/sdk/tables/azure-data-tables/CMakeLists.txt +@@ -106,6 +106,7 @@ target_include_directories( + target_link_libraries(azure-data-tables PUBLIC Azure::azure-core) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-data-tables PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-data-tables ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/template/azure-template/CMakeLists.txt b/sdk/template/azure-template/CMakeLists.txt +index 84e3d17..43f3320 100644 +--- a/sdk/template/azure-template/CMakeLists.txt ++++ b/sdk/template/azure-template/CMakeLists.txt +@@ -78,6 +78,7 @@ add_library(Azure::azure-template ALIAS azure-template) + create_code_coverage(template azure-template azure-template-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-template PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-template ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-core/metadata.xml b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-core/metadata.xml new file mode 100644 index 00000000000..5db219e6b1e --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-core/metadata.xml @@ -0,0 +1,11 @@ + + + + + chewi@gentoo.org + James Le Cuirot + + + Azure/azure-sdk-for-cpp + + diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-identity/Manifest b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-identity/Manifest new file mode 100644 index 00000000000..84bd625d629 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-identity/Manifest @@ -0,0 +1 @@ +DIST azure-sdk-for-cpp-4b913e073e50466e8b2d674e65234e7b66d7db49.tar.gz 3130918 BLAKE2B 09f85c1d984b74de2ecfe7de3953b5d4d9898dd087d5a507f4a9a26ab79782a03022adf0fe5cd27cf998fbe277279a3dc0b3cc1977a8599338229146263fffaa SHA512 d243465b248b671495cf94c6d6a53639f6976cfd888a7963e98ba7381ae2b659e39af0102be31e2ad6912b4d3c78bbfc8038318fb98cfb736f5aa99d38207d93 diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-identity/azure-identity-1.10.0.ebuild b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-identity/azure-identity-1.10.0.ebuild new file mode 100644 index 00000000000..fae8226b7eb --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-identity/azure-identity-1.10.0.ebuild @@ -0,0 +1,53 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit cmake + +COMMIT="4b913e073e50466e8b2d674e65234e7b66d7db49" +MY_P="azure-sdk-for-cpp-${COMMIT}" +DESCRIPTION="Azure SDK for C++" +HOMEPAGE="https://azure.github.io/azure-sdk-for-cpp/" +SRC_URI="https://github.com/Azure/azure-sdk-for-cpp/archive/${COMMIT}.tar.gz -> ${MY_P}.tar.gz" +S="${WORKDIR}/${MY_P}/sdk/identity/${PN}" +LICENSE="MIT" +SLOT="0/${PV}" +KEYWORDS="~amd64" +IUSE="doc" +RESTRICT="test" # Too many online tests. + +RDEPEND=" + dev-cpp/azure-core:= + dev-libs/openssl:= + net-misc/curl[ssl] +" +DEPEND=" + ${RDEPEND} +" +BDEPEND=" + virtual/pkgconfig + doc? ( app-text/doxygen ) +" + +src_prepare() { + cmake_src_prepare + cd ../../.. || die + eapply "${FILESDIR}"/azure-sdk-for-cpp-soversion.patch +} + +src_configure() { + local mycmakeargs=( + -DBUILD_DOCUMENTATION=$(usex doc) + -DWARNINGS_AS_ERRORS=no + ) + + AZURE_SDK_DISABLE_AUTO_VCPKG=yes \ + cmake_src_configure +} + +src_install() { + cmake_src_install + rm -v "${ED}"/usr/share/*/copyright || die + use doc && dodoc -r "${BUILD_DIR}"/docs/html +} diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-identity/files/azure-sdk-for-cpp-soversion.patch b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-identity/files/azure-sdk-for-cpp-soversion.patch new file mode 100644 index 00000000000..550f9f22847 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-identity/files/azure-sdk-for-cpp-soversion.patch @@ -0,0 +1,216 @@ +diff --git a/sdk/attestation/azure-security-attestation/CMakeLists.txt b/sdk/attestation/azure-security-attestation/CMakeLists.txt +index 8dec8cf..dff3461 100644 +--- a/sdk/attestation/azure-security-attestation/CMakeLists.txt ++++ b/sdk/attestation/azure-security-attestation/CMakeLists.txt +@@ -86,6 +86,7 @@ create_code_coverage(attestation azure-security-attestation azure-security-attes + + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-attestation PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-attestation ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/core/azure-core-amqp/CMakeLists.txt b/sdk/core/azure-core-amqp/CMakeLists.txt +index 3ef7bf8..e99d57f 100644 +--- a/sdk/core/azure-core-amqp/CMakeLists.txt ++++ b/sdk/core/azure-core-amqp/CMakeLists.txt +@@ -177,6 +177,7 @@ target_link_libraries(azure-core-amqp PRIVATE + PUBLIC Azure::azure-core) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-core-amqp PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-core-amqp ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt b/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt +index 23cf7d1..3834d6c 100644 +--- a/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt ++++ b/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt +@@ -80,6 +80,7 @@ if (BUILD_AZURE_CORE_TRACING_OPENTELEMETRY) + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-core-tracing-opentelemetry PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-core-tracing-opentelemetry ${AZ_LIBRARY_VERSION}) + + if(BUILD_AZURE_CORE_TRACING_OPENTELEMETRY) +diff --git a/sdk/core/azure-core/CMakeLists.txt b/sdk/core/azure-core/CMakeLists.txt +index 87c5cfd..9dbf5a0 100644 +--- a/sdk/core/azure-core/CMakeLists.txt ++++ b/sdk/core/azure-core/CMakeLists.txt +@@ -192,6 +192,7 @@ if(BUILD_TRANSPORT_WINHTTP) + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-core PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-core ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt +index 2152690..4af757c 100644 +--- a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt ++++ b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt +@@ -91,6 +91,7 @@ target_link_libraries(azure-messaging-eventhubs-checkpointstore-blob + create_code_coverage(eventhubs azure-messaging-eventhubs-checkpointstore-blob azure-messaging-eventhubs-blobcheckpointstore-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-messaging-eventhubs-checkpointstore-blob PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + #generate_documentation(azure-messaging-eventhubs-checkpointstore-blob ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-messaging-eventhubs-checkpointstore-blob ${AZ_LIBRARY_VERSION}) + +diff --git a/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt b/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt +index 0ea0b8e..e0dbe51 100644 +--- a/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt ++++ b/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt +@@ -116,6 +116,7 @@ target_compile_definitions(azure-messaging-eventhubs PRIVATE _azure_BUILDING_SDK + create_code_coverage(eventhubs azure-messaging-eventhubs azure-messaging-eventhubs-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-messaging-eventhubs PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-messaging-eventhubs ${AZ_LIBRARY_VERSION}) + + add_subdirectory(test) +diff --git a/sdk/identity/azure-identity/CMakeLists.txt b/sdk/identity/azure-identity/CMakeLists.txt +index 57fe6bb..3c21177 100644 +--- a/sdk/identity/azure-identity/CMakeLists.txt ++++ b/sdk/identity/azure-identity/CMakeLists.txt +@@ -117,6 +117,7 @@ else() + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-identity PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-identity ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt +index 5f70eb3..b065d33 100644 +--- a/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt +@@ -95,6 +95,7 @@ target_compile_definitions(azure-security-keyvault-administration PRIVATE _azure + create_code_coverage(keyvault azure-security-keyvault-administration azure-security-keyvault-administration-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-administration PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-administration ${AZ_LIBRARY_VERSION}) + if(BUILD_TESTING) + +diff --git a/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt +index 0806e09..8014038 100644 +--- a/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt +@@ -100,6 +100,7 @@ target_compile_definitions(azure-security-keyvault-certificates PRIVATE _azure_B + create_code_coverage(keyvault azure-security-keyvault-certificates azure-security-keyvault-certificates-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-certificates PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-certificates ${AZ_LIBRARY_VERSION}) + + if(BUILD_TESTING) +diff --git a/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt +index 6217fd1..2de5e64 100644 +--- a/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt +@@ -138,6 +138,7 @@ target_compile_definitions(azure-security-keyvault-keys PRIVATE _azure_BUILDING_ + create_code_coverage(keyvault azure-security-keyvault-keys azure-security-keyvault-keys-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-keys PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-keys ${AZ_LIBRARY_VERSION}) + + if(BUILD_TESTING) +diff --git a/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt +index 7cc62a8..3664d8c 100644 +--- a/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt +@@ -115,6 +115,7 @@ target_compile_definitions(azure-security-keyvault-secrets PRIVATE _azure_BUILDI + create_code_coverage(keyvault azure-security-keyvault-secrets azure-security-keyvault-secrets-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-secrets PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-secrets ${AZ_LIBRARY_VERSION}) + if(BUILD_TESTING) + +diff --git a/sdk/storage/azure-storage-blobs/CMakeLists.txt b/sdk/storage/azure-storage-blobs/CMakeLists.txt +index f87ceae..657ef33 100644 +--- a/sdk/storage/azure-storage-blobs/CMakeLists.txt ++++ b/sdk/storage/azure-storage-blobs/CMakeLists.txt +@@ -96,6 +96,7 @@ target_link_libraries(azure-storage-blobs PUBLIC Azure::azure-storage-common) + target_compile_definitions(azure-storage-blobs PRIVATE _azure_BUILDING_SDK) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-blobs PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-blobs ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-common/CMakeLists.txt b/sdk/storage/azure-storage-common/CMakeLists.txt +index 30f056d..ce90e8a 100644 +--- a/sdk/storage/azure-storage-common/CMakeLists.txt ++++ b/sdk/storage/azure-storage-common/CMakeLists.txt +@@ -107,6 +107,7 @@ else() + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-common PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-common ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-files-datalake/CMakeLists.txt b/sdk/storage/azure-storage-files-datalake/CMakeLists.txt +index 71905c8..ac82507 100644 +--- a/sdk/storage/azure-storage-files-datalake/CMakeLists.txt ++++ b/sdk/storage/azure-storage-files-datalake/CMakeLists.txt +@@ -92,6 +92,7 @@ target_include_directories( + target_link_libraries(azure-storage-files-datalake PUBLIC Azure::azure-storage-blobs) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-files-datalake PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-files-datalake ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-files-shares/CMakeLists.txt b/sdk/storage/azure-storage-files-shares/CMakeLists.txt +index 891f954..cf6cd92 100644 +--- a/sdk/storage/azure-storage-files-shares/CMakeLists.txt ++++ b/sdk/storage/azure-storage-files-shares/CMakeLists.txt +@@ -88,6 +88,7 @@ target_include_directories( + target_link_libraries(azure-storage-files-shares PUBLIC Azure::azure-storage-common) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-files-shares PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-files-shares ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-queues/CMakeLists.txt b/sdk/storage/azure-storage-queues/CMakeLists.txt +index e567623..2e340d5 100644 +--- a/sdk/storage/azure-storage-queues/CMakeLists.txt ++++ b/sdk/storage/azure-storage-queues/CMakeLists.txt +@@ -81,6 +81,7 @@ target_include_directories( + target_link_libraries(azure-storage-queues PUBLIC Azure::azure-storage-common) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-queues PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-queues ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/tables/azure-data-tables/CMakeLists.txt b/sdk/tables/azure-data-tables/CMakeLists.txt +index 038e267..d7e7976 100644 +--- a/sdk/tables/azure-data-tables/CMakeLists.txt ++++ b/sdk/tables/azure-data-tables/CMakeLists.txt +@@ -106,6 +106,7 @@ target_include_directories( + target_link_libraries(azure-data-tables PUBLIC Azure::azure-core) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-data-tables PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-data-tables ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/template/azure-template/CMakeLists.txt b/sdk/template/azure-template/CMakeLists.txt +index 84e3d17..43f3320 100644 +--- a/sdk/template/azure-template/CMakeLists.txt ++++ b/sdk/template/azure-template/CMakeLists.txt +@@ -78,6 +78,7 @@ add_library(Azure::azure-template ALIAS azure-template) + create_code_coverage(template azure-template azure-template-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-template PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-template ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-identity/metadata.xml b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-identity/metadata.xml new file mode 100644 index 00000000000..5db219e6b1e --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-identity/metadata.xml @@ -0,0 +1,11 @@ + + + + + chewi@gentoo.org + James Le Cuirot + + + Azure/azure-sdk-for-cpp + + diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-certificates/Manifest b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-certificates/Manifest new file mode 100644 index 00000000000..61c00a3d0a9 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-certificates/Manifest @@ -0,0 +1 @@ +DIST azure-sdk-for-cpp-1d22b9bc578fec09364f7271ff7bd679d713e1f2.tar.gz 2966243 BLAKE2B ca2b1ba84dc358bbdee752329bcecfac42ecf19b4b89ba6998625a3612d9387226e58c50be683eedfb5cde9678e2508a4212b95380ccb1d7451a3092b01fd27c SHA512 991a10ad5ed45b93a8681e97a77c9aa91a25c8b2622c08862471484c9cb0c94354e83553505b20f0e05472bbc984bced0130429b770931c1dbf23a9bbeb22b8c diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-certificates/azure-security-keyvault-certificates-4.2.1.ebuild b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-certificates/azure-security-keyvault-certificates-4.2.1.ebuild new file mode 100644 index 00000000000..3af53771d87 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-certificates/azure-security-keyvault-certificates-4.2.1.ebuild @@ -0,0 +1,53 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit cmake + +COMMIT="1d22b9bc578fec09364f7271ff7bd679d713e1f2" +MY_P="azure-sdk-for-cpp-${COMMIT}" +DESCRIPTION="Azure SDK for C++" +HOMEPAGE="https://azure.github.io/azure-sdk-for-cpp/" +SRC_URI="https://github.com/Azure/azure-sdk-for-cpp/archive/${COMMIT}.tar.gz -> ${MY_P}.tar.gz" +S="${WORKDIR}/${MY_P}/sdk/keyvault/${PN}" +LICENSE="MIT" +SLOT="0/${PV}" +KEYWORDS="~amd64" +IUSE="doc" +RESTRICT="test" # Too many online tests. + +RDEPEND=" + dev-cpp/azure-core:= + net-misc/curl[ssl] +" +DEPEND=" + ${RDEPEND} +" +BDEPEND=" + virtual/pkgconfig + doc? ( app-text/doxygen ) +" + +src_prepare() { + cmake_src_prepare + cd ../../.. || die + eapply "${FILESDIR}"/azure-sdk-for-cpp-doc-assets-dir.patch + eapply "${FILESDIR}"/azure-sdk-for-cpp-soversion.patch +} + +src_configure() { + local mycmakeargs=( + -DBUILD_DOCUMENTATION=$(usex doc) + -DWARNINGS_AS_ERRORS=no + ) + + AZURE_SDK_DISABLE_AUTO_VCPKG=yes \ + cmake_src_configure +} + +src_install() { + cmake_src_install + rm -v "${ED}"/usr/share/*/copyright || die + use doc && dodoc -r "${BUILD_DIR}"/docs/html +} diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-certificates/files/azure-sdk-for-cpp-doc-assets-dir.patch b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-certificates/files/azure-sdk-for-cpp-doc-assets-dir.patch new file mode 100644 index 00000000000..7346d5ae833 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-certificates/files/azure-sdk-for-cpp-doc-assets-dir.patch @@ -0,0 +1,51 @@ +From c8f662204f7858a38b485c23b387e5abdf13042c Mon Sep 17 00:00:00 2001 +From: James Le Cuirot +Date: Fri, 20 Sep 2024 17:17:50 +0100 +Subject: [PATCH] Fix building docs from subprojects by not using + CMAKE_SOURCE_DIR + +The generate_documentation function currently uses CMAKE_SOURCE_DIR to +find documentation assets at the SDK top-level, but when building from a +subproject like sdk/core/azure-core, the variable points to that +directory instead. + +Fix this by defining SDK_ROOT_DIR, which is based on PROJECT_SOURCE_DIR. +This should always work as long as each subproject calling the function +is always 3 levels down, which is currently the case. +--- + cmake-modules/AzureDoxygen.cmake | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/cmake-modules/AzureDoxygen.cmake b/cmake-modules/AzureDoxygen.cmake +index 31b2e2f..eb64c39 100644 +--- a/cmake-modules/AzureDoxygen.cmake ++++ b/cmake-modules/AzureDoxygen.cmake +@@ -14,8 +14,9 @@ function(generate_documentation PROJECT_NAME PROJECT_VERSION) + set(DOXYGEN_PROJECT_NAME ${PROJECT_NAME}) + set(DOXYGEN_PROJECT_NUMBER ${PROJECT_VERSION}) + ++ set(SDK_ROOT_DIR ${PROJECT_SOURCE_DIR}/../../..) + set(DOXYGEN_OUTPUT_DIRECTORY docs) +- set(DOXYGEN_LAYOUT_FILE ${CMAKE_SOURCE_DIR}/eng/docs/api/assets/DoxygenLayout.xml) ++ set(DOXYGEN_LAYOUT_FILE ${SDK_ROOT_DIR}/eng/docs/api/assets/DoxygenLayout.xml) + set(DOXYGEN_RECURSIVE YES) + if (MSVC) + set(DOXYGEN_WARN_FORMAT "$file($line) : $text") +@@ -45,10 +46,10 @@ function(generate_documentation PROJECT_NAME PROJECT_VERSION) + az_ + AZ_ + ) +- set(DOXYGEN_HTML_HEADER ${CMAKE_SOURCE_DIR}/eng/docs/api/assets/header.html) +- set(DOXYGEN_HTML_FOOTER ${CMAKE_SOURCE_DIR}/eng/docs/api/assets/footer.html) +- set(DOXYGEN_HTML_STYLESHEET ${CMAKE_SOURCE_DIR}/eng/docs/api/assets/style.css) +- set(DOXYGEN_PROJECT_LOGO ${CMAKE_SOURCE_DIR}/eng/common/docgeneration/assets/logo.svg) ++ set(DOXYGEN_HTML_HEADER ${SDK_ROOT_DIR}/eng/docs/api/assets/header.html) ++ set(DOXYGEN_HTML_FOOTER ${SDK_ROOT_DIR}/eng/docs/api/assets/footer.html) ++ set(DOXYGEN_HTML_STYLESHEET ${SDK_ROOT_DIR}/eng/docs/api/assets/style.css) ++ set(DOXYGEN_PROJECT_LOGO ${SDK_ROOT_DIR}/eng/common/docgeneration/assets/logo.svg) + + set(DOXYGEN_GENERATE_XML YES) + set(DOXYGEN_GENERATE_LATEX NO) +-- +2.46.0 + diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-certificates/files/azure-sdk-for-cpp-soversion.patch b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-certificates/files/azure-sdk-for-cpp-soversion.patch new file mode 100644 index 00000000000..550f9f22847 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-certificates/files/azure-sdk-for-cpp-soversion.patch @@ -0,0 +1,216 @@ +diff --git a/sdk/attestation/azure-security-attestation/CMakeLists.txt b/sdk/attestation/azure-security-attestation/CMakeLists.txt +index 8dec8cf..dff3461 100644 +--- a/sdk/attestation/azure-security-attestation/CMakeLists.txt ++++ b/sdk/attestation/azure-security-attestation/CMakeLists.txt +@@ -86,6 +86,7 @@ create_code_coverage(attestation azure-security-attestation azure-security-attes + + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-attestation PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-attestation ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/core/azure-core-amqp/CMakeLists.txt b/sdk/core/azure-core-amqp/CMakeLists.txt +index 3ef7bf8..e99d57f 100644 +--- a/sdk/core/azure-core-amqp/CMakeLists.txt ++++ b/sdk/core/azure-core-amqp/CMakeLists.txt +@@ -177,6 +177,7 @@ target_link_libraries(azure-core-amqp PRIVATE + PUBLIC Azure::azure-core) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-core-amqp PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-core-amqp ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt b/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt +index 23cf7d1..3834d6c 100644 +--- a/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt ++++ b/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt +@@ -80,6 +80,7 @@ if (BUILD_AZURE_CORE_TRACING_OPENTELEMETRY) + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-core-tracing-opentelemetry PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-core-tracing-opentelemetry ${AZ_LIBRARY_VERSION}) + + if(BUILD_AZURE_CORE_TRACING_OPENTELEMETRY) +diff --git a/sdk/core/azure-core/CMakeLists.txt b/sdk/core/azure-core/CMakeLists.txt +index 87c5cfd..9dbf5a0 100644 +--- a/sdk/core/azure-core/CMakeLists.txt ++++ b/sdk/core/azure-core/CMakeLists.txt +@@ -192,6 +192,7 @@ if(BUILD_TRANSPORT_WINHTTP) + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-core PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-core ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt +index 2152690..4af757c 100644 +--- a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt ++++ b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt +@@ -91,6 +91,7 @@ target_link_libraries(azure-messaging-eventhubs-checkpointstore-blob + create_code_coverage(eventhubs azure-messaging-eventhubs-checkpointstore-blob azure-messaging-eventhubs-blobcheckpointstore-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-messaging-eventhubs-checkpointstore-blob PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + #generate_documentation(azure-messaging-eventhubs-checkpointstore-blob ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-messaging-eventhubs-checkpointstore-blob ${AZ_LIBRARY_VERSION}) + +diff --git a/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt b/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt +index 0ea0b8e..e0dbe51 100644 +--- a/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt ++++ b/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt +@@ -116,6 +116,7 @@ target_compile_definitions(azure-messaging-eventhubs PRIVATE _azure_BUILDING_SDK + create_code_coverage(eventhubs azure-messaging-eventhubs azure-messaging-eventhubs-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-messaging-eventhubs PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-messaging-eventhubs ${AZ_LIBRARY_VERSION}) + + add_subdirectory(test) +diff --git a/sdk/identity/azure-identity/CMakeLists.txt b/sdk/identity/azure-identity/CMakeLists.txt +index 57fe6bb..3c21177 100644 +--- a/sdk/identity/azure-identity/CMakeLists.txt ++++ b/sdk/identity/azure-identity/CMakeLists.txt +@@ -117,6 +117,7 @@ else() + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-identity PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-identity ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt +index 5f70eb3..b065d33 100644 +--- a/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt +@@ -95,6 +95,7 @@ target_compile_definitions(azure-security-keyvault-administration PRIVATE _azure + create_code_coverage(keyvault azure-security-keyvault-administration azure-security-keyvault-administration-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-administration PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-administration ${AZ_LIBRARY_VERSION}) + if(BUILD_TESTING) + +diff --git a/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt +index 0806e09..8014038 100644 +--- a/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt +@@ -100,6 +100,7 @@ target_compile_definitions(azure-security-keyvault-certificates PRIVATE _azure_B + create_code_coverage(keyvault azure-security-keyvault-certificates azure-security-keyvault-certificates-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-certificates PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-certificates ${AZ_LIBRARY_VERSION}) + + if(BUILD_TESTING) +diff --git a/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt +index 6217fd1..2de5e64 100644 +--- a/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt +@@ -138,6 +138,7 @@ target_compile_definitions(azure-security-keyvault-keys PRIVATE _azure_BUILDING_ + create_code_coverage(keyvault azure-security-keyvault-keys azure-security-keyvault-keys-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-keys PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-keys ${AZ_LIBRARY_VERSION}) + + if(BUILD_TESTING) +diff --git a/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt +index 7cc62a8..3664d8c 100644 +--- a/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt +@@ -115,6 +115,7 @@ target_compile_definitions(azure-security-keyvault-secrets PRIVATE _azure_BUILDI + create_code_coverage(keyvault azure-security-keyvault-secrets azure-security-keyvault-secrets-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-secrets PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-secrets ${AZ_LIBRARY_VERSION}) + if(BUILD_TESTING) + +diff --git a/sdk/storage/azure-storage-blobs/CMakeLists.txt b/sdk/storage/azure-storage-blobs/CMakeLists.txt +index f87ceae..657ef33 100644 +--- a/sdk/storage/azure-storage-blobs/CMakeLists.txt ++++ b/sdk/storage/azure-storage-blobs/CMakeLists.txt +@@ -96,6 +96,7 @@ target_link_libraries(azure-storage-blobs PUBLIC Azure::azure-storage-common) + target_compile_definitions(azure-storage-blobs PRIVATE _azure_BUILDING_SDK) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-blobs PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-blobs ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-common/CMakeLists.txt b/sdk/storage/azure-storage-common/CMakeLists.txt +index 30f056d..ce90e8a 100644 +--- a/sdk/storage/azure-storage-common/CMakeLists.txt ++++ b/sdk/storage/azure-storage-common/CMakeLists.txt +@@ -107,6 +107,7 @@ else() + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-common PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-common ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-files-datalake/CMakeLists.txt b/sdk/storage/azure-storage-files-datalake/CMakeLists.txt +index 71905c8..ac82507 100644 +--- a/sdk/storage/azure-storage-files-datalake/CMakeLists.txt ++++ b/sdk/storage/azure-storage-files-datalake/CMakeLists.txt +@@ -92,6 +92,7 @@ target_include_directories( + target_link_libraries(azure-storage-files-datalake PUBLIC Azure::azure-storage-blobs) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-files-datalake PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-files-datalake ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-files-shares/CMakeLists.txt b/sdk/storage/azure-storage-files-shares/CMakeLists.txt +index 891f954..cf6cd92 100644 +--- a/sdk/storage/azure-storage-files-shares/CMakeLists.txt ++++ b/sdk/storage/azure-storage-files-shares/CMakeLists.txt +@@ -88,6 +88,7 @@ target_include_directories( + target_link_libraries(azure-storage-files-shares PUBLIC Azure::azure-storage-common) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-files-shares PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-files-shares ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-queues/CMakeLists.txt b/sdk/storage/azure-storage-queues/CMakeLists.txt +index e567623..2e340d5 100644 +--- a/sdk/storage/azure-storage-queues/CMakeLists.txt ++++ b/sdk/storage/azure-storage-queues/CMakeLists.txt +@@ -81,6 +81,7 @@ target_include_directories( + target_link_libraries(azure-storage-queues PUBLIC Azure::azure-storage-common) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-queues PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-queues ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/tables/azure-data-tables/CMakeLists.txt b/sdk/tables/azure-data-tables/CMakeLists.txt +index 038e267..d7e7976 100644 +--- a/sdk/tables/azure-data-tables/CMakeLists.txt ++++ b/sdk/tables/azure-data-tables/CMakeLists.txt +@@ -106,6 +106,7 @@ target_include_directories( + target_link_libraries(azure-data-tables PUBLIC Azure::azure-core) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-data-tables PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-data-tables ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/template/azure-template/CMakeLists.txt b/sdk/template/azure-template/CMakeLists.txt +index 84e3d17..43f3320 100644 +--- a/sdk/template/azure-template/CMakeLists.txt ++++ b/sdk/template/azure-template/CMakeLists.txt +@@ -78,6 +78,7 @@ add_library(Azure::azure-template ALIAS azure-template) + create_code_coverage(template azure-template azure-template-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-template PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-template ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-certificates/metadata.xml b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-certificates/metadata.xml new file mode 100644 index 00000000000..5db219e6b1e --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-certificates/metadata.xml @@ -0,0 +1,11 @@ + + + + + chewi@gentoo.org + James Le Cuirot + + + Azure/azure-sdk-for-cpp + + diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-keys/Manifest b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-keys/Manifest new file mode 100644 index 00000000000..61c00a3d0a9 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-keys/Manifest @@ -0,0 +1 @@ +DIST azure-sdk-for-cpp-1d22b9bc578fec09364f7271ff7bd679d713e1f2.tar.gz 2966243 BLAKE2B ca2b1ba84dc358bbdee752329bcecfac42ecf19b4b89ba6998625a3612d9387226e58c50be683eedfb5cde9678e2508a4212b95380ccb1d7451a3092b01fd27c SHA512 991a10ad5ed45b93a8681e97a77c9aa91a25c8b2622c08862471484c9cb0c94354e83553505b20f0e05472bbc984bced0130429b770931c1dbf23a9bbeb22b8c diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-keys/azure-security-keyvault-keys-4.4.1.ebuild b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-keys/azure-security-keyvault-keys-4.4.1.ebuild new file mode 100644 index 00000000000..3af53771d87 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-keys/azure-security-keyvault-keys-4.4.1.ebuild @@ -0,0 +1,53 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit cmake + +COMMIT="1d22b9bc578fec09364f7271ff7bd679d713e1f2" +MY_P="azure-sdk-for-cpp-${COMMIT}" +DESCRIPTION="Azure SDK for C++" +HOMEPAGE="https://azure.github.io/azure-sdk-for-cpp/" +SRC_URI="https://github.com/Azure/azure-sdk-for-cpp/archive/${COMMIT}.tar.gz -> ${MY_P}.tar.gz" +S="${WORKDIR}/${MY_P}/sdk/keyvault/${PN}" +LICENSE="MIT" +SLOT="0/${PV}" +KEYWORDS="~amd64" +IUSE="doc" +RESTRICT="test" # Too many online tests. + +RDEPEND=" + dev-cpp/azure-core:= + net-misc/curl[ssl] +" +DEPEND=" + ${RDEPEND} +" +BDEPEND=" + virtual/pkgconfig + doc? ( app-text/doxygen ) +" + +src_prepare() { + cmake_src_prepare + cd ../../.. || die + eapply "${FILESDIR}"/azure-sdk-for-cpp-doc-assets-dir.patch + eapply "${FILESDIR}"/azure-sdk-for-cpp-soversion.patch +} + +src_configure() { + local mycmakeargs=( + -DBUILD_DOCUMENTATION=$(usex doc) + -DWARNINGS_AS_ERRORS=no + ) + + AZURE_SDK_DISABLE_AUTO_VCPKG=yes \ + cmake_src_configure +} + +src_install() { + cmake_src_install + rm -v "${ED}"/usr/share/*/copyright || die + use doc && dodoc -r "${BUILD_DIR}"/docs/html +} diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-keys/files/azure-sdk-for-cpp-doc-assets-dir.patch b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-keys/files/azure-sdk-for-cpp-doc-assets-dir.patch new file mode 100644 index 00000000000..7346d5ae833 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-keys/files/azure-sdk-for-cpp-doc-assets-dir.patch @@ -0,0 +1,51 @@ +From c8f662204f7858a38b485c23b387e5abdf13042c Mon Sep 17 00:00:00 2001 +From: James Le Cuirot +Date: Fri, 20 Sep 2024 17:17:50 +0100 +Subject: [PATCH] Fix building docs from subprojects by not using + CMAKE_SOURCE_DIR + +The generate_documentation function currently uses CMAKE_SOURCE_DIR to +find documentation assets at the SDK top-level, but when building from a +subproject like sdk/core/azure-core, the variable points to that +directory instead. + +Fix this by defining SDK_ROOT_DIR, which is based on PROJECT_SOURCE_DIR. +This should always work as long as each subproject calling the function +is always 3 levels down, which is currently the case. +--- + cmake-modules/AzureDoxygen.cmake | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/cmake-modules/AzureDoxygen.cmake b/cmake-modules/AzureDoxygen.cmake +index 31b2e2f..eb64c39 100644 +--- a/cmake-modules/AzureDoxygen.cmake ++++ b/cmake-modules/AzureDoxygen.cmake +@@ -14,8 +14,9 @@ function(generate_documentation PROJECT_NAME PROJECT_VERSION) + set(DOXYGEN_PROJECT_NAME ${PROJECT_NAME}) + set(DOXYGEN_PROJECT_NUMBER ${PROJECT_VERSION}) + ++ set(SDK_ROOT_DIR ${PROJECT_SOURCE_DIR}/../../..) + set(DOXYGEN_OUTPUT_DIRECTORY docs) +- set(DOXYGEN_LAYOUT_FILE ${CMAKE_SOURCE_DIR}/eng/docs/api/assets/DoxygenLayout.xml) ++ set(DOXYGEN_LAYOUT_FILE ${SDK_ROOT_DIR}/eng/docs/api/assets/DoxygenLayout.xml) + set(DOXYGEN_RECURSIVE YES) + if (MSVC) + set(DOXYGEN_WARN_FORMAT "$file($line) : $text") +@@ -45,10 +46,10 @@ function(generate_documentation PROJECT_NAME PROJECT_VERSION) + az_ + AZ_ + ) +- set(DOXYGEN_HTML_HEADER ${CMAKE_SOURCE_DIR}/eng/docs/api/assets/header.html) +- set(DOXYGEN_HTML_FOOTER ${CMAKE_SOURCE_DIR}/eng/docs/api/assets/footer.html) +- set(DOXYGEN_HTML_STYLESHEET ${CMAKE_SOURCE_DIR}/eng/docs/api/assets/style.css) +- set(DOXYGEN_PROJECT_LOGO ${CMAKE_SOURCE_DIR}/eng/common/docgeneration/assets/logo.svg) ++ set(DOXYGEN_HTML_HEADER ${SDK_ROOT_DIR}/eng/docs/api/assets/header.html) ++ set(DOXYGEN_HTML_FOOTER ${SDK_ROOT_DIR}/eng/docs/api/assets/footer.html) ++ set(DOXYGEN_HTML_STYLESHEET ${SDK_ROOT_DIR}/eng/docs/api/assets/style.css) ++ set(DOXYGEN_PROJECT_LOGO ${SDK_ROOT_DIR}/eng/common/docgeneration/assets/logo.svg) + + set(DOXYGEN_GENERATE_XML YES) + set(DOXYGEN_GENERATE_LATEX NO) +-- +2.46.0 + diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-keys/files/azure-sdk-for-cpp-soversion.patch b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-keys/files/azure-sdk-for-cpp-soversion.patch new file mode 100644 index 00000000000..550f9f22847 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-keys/files/azure-sdk-for-cpp-soversion.patch @@ -0,0 +1,216 @@ +diff --git a/sdk/attestation/azure-security-attestation/CMakeLists.txt b/sdk/attestation/azure-security-attestation/CMakeLists.txt +index 8dec8cf..dff3461 100644 +--- a/sdk/attestation/azure-security-attestation/CMakeLists.txt ++++ b/sdk/attestation/azure-security-attestation/CMakeLists.txt +@@ -86,6 +86,7 @@ create_code_coverage(attestation azure-security-attestation azure-security-attes + + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-attestation PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-attestation ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/core/azure-core-amqp/CMakeLists.txt b/sdk/core/azure-core-amqp/CMakeLists.txt +index 3ef7bf8..e99d57f 100644 +--- a/sdk/core/azure-core-amqp/CMakeLists.txt ++++ b/sdk/core/azure-core-amqp/CMakeLists.txt +@@ -177,6 +177,7 @@ target_link_libraries(azure-core-amqp PRIVATE + PUBLIC Azure::azure-core) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-core-amqp PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-core-amqp ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt b/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt +index 23cf7d1..3834d6c 100644 +--- a/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt ++++ b/sdk/core/azure-core-tracing-opentelemetry/CMakeLists.txt +@@ -80,6 +80,7 @@ if (BUILD_AZURE_CORE_TRACING_OPENTELEMETRY) + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-core-tracing-opentelemetry PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-core-tracing-opentelemetry ${AZ_LIBRARY_VERSION}) + + if(BUILD_AZURE_CORE_TRACING_OPENTELEMETRY) +diff --git a/sdk/core/azure-core/CMakeLists.txt b/sdk/core/azure-core/CMakeLists.txt +index 87c5cfd..9dbf5a0 100644 +--- a/sdk/core/azure-core/CMakeLists.txt ++++ b/sdk/core/azure-core/CMakeLists.txt +@@ -192,6 +192,7 @@ if(BUILD_TRANSPORT_WINHTTP) + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-core PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-core ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt +index 2152690..4af757c 100644 +--- a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt ++++ b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/CMakeLists.txt +@@ -91,6 +91,7 @@ target_link_libraries(azure-messaging-eventhubs-checkpointstore-blob + create_code_coverage(eventhubs azure-messaging-eventhubs-checkpointstore-blob azure-messaging-eventhubs-blobcheckpointstore-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-messaging-eventhubs-checkpointstore-blob PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + #generate_documentation(azure-messaging-eventhubs-checkpointstore-blob ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-messaging-eventhubs-checkpointstore-blob ${AZ_LIBRARY_VERSION}) + +diff --git a/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt b/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt +index 0ea0b8e..e0dbe51 100644 +--- a/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt ++++ b/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt +@@ -116,6 +116,7 @@ target_compile_definitions(azure-messaging-eventhubs PRIVATE _azure_BUILDING_SDK + create_code_coverage(eventhubs azure-messaging-eventhubs azure-messaging-eventhubs-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-messaging-eventhubs PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-messaging-eventhubs ${AZ_LIBRARY_VERSION}) + + add_subdirectory(test) +diff --git a/sdk/identity/azure-identity/CMakeLists.txt b/sdk/identity/azure-identity/CMakeLists.txt +index 57fe6bb..3c21177 100644 +--- a/sdk/identity/azure-identity/CMakeLists.txt ++++ b/sdk/identity/azure-identity/CMakeLists.txt +@@ -117,6 +117,7 @@ else() + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-identity PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-identity ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt +index 5f70eb3..b065d33 100644 +--- a/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-administration/CMakeLists.txt +@@ -95,6 +95,7 @@ target_compile_definitions(azure-security-keyvault-administration PRIVATE _azure + create_code_coverage(keyvault azure-security-keyvault-administration azure-security-keyvault-administration-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-administration PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-administration ${AZ_LIBRARY_VERSION}) + if(BUILD_TESTING) + +diff --git a/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt +index 0806e09..8014038 100644 +--- a/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-certificates/CMakeLists.txt +@@ -100,6 +100,7 @@ target_compile_definitions(azure-security-keyvault-certificates PRIVATE _azure_B + create_code_coverage(keyvault azure-security-keyvault-certificates azure-security-keyvault-certificates-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-certificates PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-certificates ${AZ_LIBRARY_VERSION}) + + if(BUILD_TESTING) +diff --git a/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt +index 6217fd1..2de5e64 100644 +--- a/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-keys/CMakeLists.txt +@@ -138,6 +138,7 @@ target_compile_definitions(azure-security-keyvault-keys PRIVATE _azure_BUILDING_ + create_code_coverage(keyvault azure-security-keyvault-keys azure-security-keyvault-keys-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-keys PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-keys ${AZ_LIBRARY_VERSION}) + + if(BUILD_TESTING) +diff --git a/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt +index 7cc62a8..3664d8c 100644 +--- a/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt ++++ b/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt +@@ -115,6 +115,7 @@ target_compile_definitions(azure-security-keyvault-secrets PRIVATE _azure_BUILDI + create_code_coverage(keyvault azure-security-keyvault-secrets azure-security-keyvault-secrets-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-security-keyvault-secrets PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-security-keyvault-secrets ${AZ_LIBRARY_VERSION}) + if(BUILD_TESTING) + +diff --git a/sdk/storage/azure-storage-blobs/CMakeLists.txt b/sdk/storage/azure-storage-blobs/CMakeLists.txt +index f87ceae..657ef33 100644 +--- a/sdk/storage/azure-storage-blobs/CMakeLists.txt ++++ b/sdk/storage/azure-storage-blobs/CMakeLists.txt +@@ -96,6 +96,7 @@ target_link_libraries(azure-storage-blobs PUBLIC Azure::azure-storage-common) + target_compile_definitions(azure-storage-blobs PRIVATE _azure_BUILDING_SDK) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-blobs PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-blobs ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-common/CMakeLists.txt b/sdk/storage/azure-storage-common/CMakeLists.txt +index 30f056d..ce90e8a 100644 +--- a/sdk/storage/azure-storage-common/CMakeLists.txt ++++ b/sdk/storage/azure-storage-common/CMakeLists.txt +@@ -107,6 +107,7 @@ else() + endif() + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-common PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-common ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-files-datalake/CMakeLists.txt b/sdk/storage/azure-storage-files-datalake/CMakeLists.txt +index 71905c8..ac82507 100644 +--- a/sdk/storage/azure-storage-files-datalake/CMakeLists.txt ++++ b/sdk/storage/azure-storage-files-datalake/CMakeLists.txt +@@ -92,6 +92,7 @@ target_include_directories( + target_link_libraries(azure-storage-files-datalake PUBLIC Azure::azure-storage-blobs) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-files-datalake PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-files-datalake ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-files-shares/CMakeLists.txt b/sdk/storage/azure-storage-files-shares/CMakeLists.txt +index 891f954..cf6cd92 100644 +--- a/sdk/storage/azure-storage-files-shares/CMakeLists.txt ++++ b/sdk/storage/azure-storage-files-shares/CMakeLists.txt +@@ -88,6 +88,7 @@ target_include_directories( + target_link_libraries(azure-storage-files-shares PUBLIC Azure::azure-storage-common) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-files-shares PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-files-shares ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/storage/azure-storage-queues/CMakeLists.txt b/sdk/storage/azure-storage-queues/CMakeLists.txt +index e567623..2e340d5 100644 +--- a/sdk/storage/azure-storage-queues/CMakeLists.txt ++++ b/sdk/storage/azure-storage-queues/CMakeLists.txt +@@ -81,6 +81,7 @@ target_include_directories( + target_link_libraries(azure-storage-queues PUBLIC Azure::azure-storage-common) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-storage-queues PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-storage-queues ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/tables/azure-data-tables/CMakeLists.txt b/sdk/tables/azure-data-tables/CMakeLists.txt +index 038e267..d7e7976 100644 +--- a/sdk/tables/azure-data-tables/CMakeLists.txt ++++ b/sdk/tables/azure-data-tables/CMakeLists.txt +@@ -106,6 +106,7 @@ target_include_directories( + target_link_libraries(azure-data-tables PUBLIC Azure::azure-core) + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-data-tables PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-data-tables ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( +diff --git a/sdk/template/azure-template/CMakeLists.txt b/sdk/template/azure-template/CMakeLists.txt +index 84e3d17..43f3320 100644 +--- a/sdk/template/azure-template/CMakeLists.txt ++++ b/sdk/template/azure-template/CMakeLists.txt +@@ -78,6 +78,7 @@ add_library(Azure::azure-template ALIAS azure-template) + create_code_coverage(template azure-template azure-template-test "tests?/*;samples?/*") + + get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") ++set_target_properties(azure-template PROPERTIES VERSION ${AZ_LIBRARY_VERSION}) + generate_documentation(azure-template ${AZ_LIBRARY_VERSION}) + + az_vcpkg_export( diff --git a/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-keys/metadata.xml b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-keys/metadata.xml new file mode 100644 index 00000000000..5db219e6b1e --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-cpp/azure-security-keyvault-keys/metadata.xml @@ -0,0 +1,11 @@ + + + + + chewi@gentoo.org + James Le Cuirot + + + Azure/azure-sdk-for-cpp + + diff --git a/sdk_container/src/third_party/portage-stable/dev-python/cffi/Manifest b/sdk_container/src/third_party/portage-stable/dev-python/cffi/Manifest new file mode 100644 index 00000000000..1a055ef42bd --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/cffi/Manifest @@ -0,0 +1,5 @@ +DIST cffi-1.16.0.tar.gz 512873 BLAKE2B 9e8d107b3124a072e559c4a536b54a172e90f9fe51d8184dacc2914a8ffa84f2682eee9c90401325dfb0f36f3f8ea0456afc93e2b85a4fef5f07ae4475e0a76b SHA512 fd2588115092202aa9289c9d4e0a0b3e264b5e9ec1dc192950f31aeb412fd9f9d4e5c96a3f9c6762987b58ccc1e229f2012ddda89211797104df672d8ed51152 +DIST cffi-1.17.0.tar.gz 516073 BLAKE2B e050689b58b4a34e3f605f84b3b6a59ec44359bfb042796f82e1acb6349b65ca37f9fb7a0d4ffc7fe40b85416288dcc1f3496968c4fb3f36cdd2c0042658f7b1 SHA512 8516abe177c2acfc31ede401287956cc4dc486b26ed9c4752811be71dc6bc94af3adf1f1f685a94e7242f052b74768bfbbb30ce41a3c23b9259c91449347566e +DIST cffi-1.17.0rc1.tar.gz 516063 BLAKE2B 02f25fde28a070c314deb5870d2285a0cfd2fd10d0136b3c5459d4bb11454722d61dfe0e5f27a7268a4aca8cadb2a9df045340094bcf98f1692f54ddea6df714 SHA512 757ccaf09a745cd04a31d0b2fcc46f438269b79b88c4a89aa7dd2f0dd1bc1b64fb9f9fde2461407e1c0482c1c64e837283e21d0b46dbcb0c4ccd5e54a8319a0e +DIST cffi-1.17.1.tar.gz 516621 BLAKE2B 902844a14c0765ada6adf5054a9462a195b49b2ea4d7441deeff97dd6d9209accd29257697002ee1bad7e143ebf983a2d98077b17e08b060dd1ee75dc682e3d8 SHA512 907129891d56351ca5cb885aae62334ad432321826d6eddfaa32195b4c7b7689a80333e6d14d0aab479a646aba148b9852c0815b80344dfffa4f183a5e74372c +DIST cffi-d7f750b1b1c5ea4da5aa537b9baba0e01b0ce843.gh.tar.gz 523050 BLAKE2B 498085e9bc497eb1abf2d2e26e2cdb9d7544509b2c1686b306930c2da8a39a5ef133b77302761b44d5231c5255ef30cbd22579c79921dc2dc71e723ff5624939 SHA512 a0d1eb7bf8df12331d3493d86894ba062f7a15f4e7421863d44e264d4ca40ef864c7574d42cb7a4f2ea44ab80242942d6f4c8772c64b8dd0789aeb9f1908fc89 diff --git a/sdk_container/src/third_party/portage-stable/dev-python/cffi/cffi-1.16.0.ebuild b/sdk_container/src/third_party/portage-stable/dev-python/cffi/cffi-1.16.0.ebuild new file mode 100644 index 00000000000..448d0777dc8 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/cffi/cffi-1.16.0.ebuild @@ -0,0 +1,72 @@ +# Copyright 1999-2023 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# please keep this ebuild at EAPI 8 -- sys-apps/portage dep +EAPI=8 + +# py3.12 support is experimental, expect problems in revdeps +DISTUTILS_EXT=1 +DISTUTILS_USE_PEP517=setuptools +# DO NOT ADD pypy to PYTHON_COMPAT +# pypy bundles a modified version of cffi. Use python_gen_cond_dep instead. +PYTHON_COMPAT=( python3_{10..12} ) + +inherit distutils-r1 toolchain-funcs pypi + +DESCRIPTION="Foreign Function Interface for Python calling C code" +HOMEPAGE=" + https://cffi.readthedocs.io/ + https://pypi.org/project/cffi/ +" + +LICENSE="MIT" +SLOT="0/${PV}" +KEYWORDS="~alpha amd64 arm arm64 hppa ~loong ~m68k ~mips ppc ppc64 ~riscv ~s390 sparc x86 ~amd64-linux ~x86-linux ~arm64-macos ~ppc-macos ~x64-macos ~x64-solaris" + +# Needs recent libffi for HPPA fixes +DEPEND=" + >=dev-libs/libffi-3.4.4-r1:= +" +# setuptools as a modern distutils provider +RDEPEND=" + ${DEPEND} + dev-python/pycparser[${PYTHON_USEDEP}] + dev-python/setuptools[${PYTHON_USEDEP}] +" +BDEPEND=" + ${RDEPEND} + virtual/pkgconfig + test? ( + dev-python/py[${PYTHON_USEDEP}] + ) +" + +distutils_enable_sphinx doc/source +distutils_enable_tests pytest + +PATCHES=( + "${FILESDIR}"/cffi-1.14.0-darwin-no-brew.patch +) + +src_prepare() { + if [[ ${CHOST} == *darwin* ]] ; then + # Don't obsessively try to find libffi + sed -i -e "s/.*\-iwithsysroot\/usr\/include\/ffi.*/\tpass/" setup.py || die + fi + distutils-r1_src_prepare +} + +src_configure() { + tc-export PKG_CONFIG +} + +python_test() { + local EPYTEST_IGNORE=( + # these tests call pip + testing/cffi0/test_zintegration.py + ) + + "${EPYTHON}" -c "import _cffi_backend as backend" || die + local -x PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 + epytest src/c testing +} diff --git a/sdk_container/src/third_party/portage-stable/dev-python/cffi/cffi-1.17.0.ebuild b/sdk_container/src/third_party/portage-stable/dev-python/cffi/cffi-1.17.0.ebuild new file mode 100644 index 00000000000..12e59daf20e --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/cffi/cffi-1.17.0.ebuild @@ -0,0 +1,71 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# please keep this ebuild at EAPI 8 -- sys-apps/portage dep +EAPI=8 + +DISTUTILS_EXT=1 +DISTUTILS_USE_PEP517=setuptools +# DO NOT ADD pypy to PYTHON_COMPAT +# pypy bundles a modified version of cffi. Use python_gen_cond_dep instead. +PYTHON_COMPAT=( python3_{10..13} ) + +inherit distutils-r1 toolchain-funcs pypi + +DESCRIPTION="Foreign Function Interface for Python calling C code" +HOMEPAGE=" + https://cffi.readthedocs.io/ + https://pypi.org/project/cffi/ +" + +LICENSE="MIT" +SLOT="0/${PV}" +KEYWORDS="~alpha amd64 arm arm64 ~hppa ~loong ~m68k ~mips ppc ppc64 ~riscv ~s390 sparc x86 ~amd64-linux ~x86-linux ~arm64-macos ~ppc-macos ~x64-macos ~x64-solaris" + +# Needs recent libffi for HPPA fixes +DEPEND=" + >=dev-libs/libffi-3.4.4-r1:= +" +# setuptools as a modern distutils provider +RDEPEND=" + ${DEPEND} + dev-python/pycparser[${PYTHON_USEDEP}] + dev-python/setuptools[${PYTHON_USEDEP}] +" +BDEPEND=" + ${RDEPEND} + virtual/pkgconfig + test? ( + dev-python/py[${PYTHON_USEDEP}] + ) +" + +distutils_enable_sphinx doc/source +distutils_enable_tests pytest + +PATCHES=( + "${FILESDIR}"/cffi-1.14.0-darwin-no-brew.patch +) + +src_prepare() { + if [[ ${CHOST} == *darwin* ]] ; then + # Don't obsessively try to find libffi + sed -i -e "s/.*\-iwithsysroot\/usr\/include\/ffi.*/\tpass/" setup.py || die + fi + distutils-r1_src_prepare +} + +src_configure() { + tc-export PKG_CONFIG +} + +python_test() { + local EPYTEST_IGNORE=( + # these tests call pip + testing/cffi0/test_zintegration.py + ) + + "${EPYTHON}" -c "import _cffi_backend as backend" || die + local -x PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 + epytest src/c testing +} diff --git a/sdk_container/src/third_party/portage-stable/dev-python/cffi/cffi-1.17.0_pre20240424.ebuild b/sdk_container/src/third_party/portage-stable/dev-python/cffi/cffi-1.17.0_pre20240424.ebuild new file mode 100644 index 00000000000..a9b719b340c --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/cffi/cffi-1.17.0_pre20240424.ebuild @@ -0,0 +1,79 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# please keep this ebuild at EAPI 8 -- sys-apps/portage dep +EAPI=8 + +DISTUTILS_EXT=1 +DISTUTILS_USE_PEP517=setuptools +# DO NOT ADD pypy to PYTHON_COMPAT +# pypy bundles a modified version of cffi. Use python_gen_cond_dep instead. +PYTHON_COMPAT=( python3_{10..13} ) + +inherit distutils-r1 toolchain-funcs + +EGIT_COMMIT=d7f750b1b1c5ea4da5aa537b9baba0e01b0ce843 +MY_P=${PN}-${EGIT_COMMIT} + +DESCRIPTION="Foreign Function Interface for Python calling C code" +HOMEPAGE=" + https://cffi.readthedocs.io/ + https://pypi.org/project/cffi/ +" +SRC_URI=" + https://github.com/python-cffi/cffi/archive/${EGIT_COMMIT}.tar.gz + -> ${MY_P}.gh.tar.gz +" +S=${WORKDIR}/${MY_P} + +LICENSE="MIT" +SLOT="0/${PV}" +KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~loong ~m68k ~mips ~ppc ~ppc64 ~riscv ~s390 ~sparc ~x86 ~amd64-linux ~x86-linux ~arm64-macos ~ppc-macos ~x64-macos ~x64-solaris" + +# Needs recent libffi for HPPA fixes +DEPEND=" + >=dev-libs/libffi-3.4.4-r1:= +" +# setuptools as a modern distutils provider +RDEPEND=" + ${DEPEND} + dev-python/pycparser[${PYTHON_USEDEP}] + dev-python/setuptools[${PYTHON_USEDEP}] +" +BDEPEND=" + ${RDEPEND} + virtual/pkgconfig + test? ( + dev-python/py[${PYTHON_USEDEP}] + ) +" + +distutils_enable_sphinx doc/source +distutils_enable_tests pytest + +PATCHES=( + "${FILESDIR}"/cffi-1.14.0-darwin-no-brew.patch +) + +src_prepare() { + if [[ ${CHOST} == *darwin* ]] ; then + # Don't obsessively try to find libffi + sed -i -e "s/.*\-iwithsysroot\/usr\/include\/ffi.*/\tpass/" setup.py || die + fi + distutils-r1_src_prepare +} + +src_configure() { + tc-export PKG_CONFIG +} + +python_test() { + local EPYTEST_IGNORE=( + # these tests call pip + testing/cffi0/test_zintegration.py + ) + + "${EPYTHON}" -c "import _cffi_backend as backend" || die + local -x PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 + epytest src/c testing +} diff --git a/sdk_container/src/third_party/portage-stable/dev-python/cffi/cffi-1.17.0_rc1.ebuild b/sdk_container/src/third_party/portage-stable/dev-python/cffi/cffi-1.17.0_rc1.ebuild new file mode 100644 index 00000000000..12e59daf20e --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/cffi/cffi-1.17.0_rc1.ebuild @@ -0,0 +1,71 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# please keep this ebuild at EAPI 8 -- sys-apps/portage dep +EAPI=8 + +DISTUTILS_EXT=1 +DISTUTILS_USE_PEP517=setuptools +# DO NOT ADD pypy to PYTHON_COMPAT +# pypy bundles a modified version of cffi. Use python_gen_cond_dep instead. +PYTHON_COMPAT=( python3_{10..13} ) + +inherit distutils-r1 toolchain-funcs pypi + +DESCRIPTION="Foreign Function Interface for Python calling C code" +HOMEPAGE=" + https://cffi.readthedocs.io/ + https://pypi.org/project/cffi/ +" + +LICENSE="MIT" +SLOT="0/${PV}" +KEYWORDS="~alpha amd64 arm arm64 ~hppa ~loong ~m68k ~mips ppc ppc64 ~riscv ~s390 sparc x86 ~amd64-linux ~x86-linux ~arm64-macos ~ppc-macos ~x64-macos ~x64-solaris" + +# Needs recent libffi for HPPA fixes +DEPEND=" + >=dev-libs/libffi-3.4.4-r1:= +" +# setuptools as a modern distutils provider +RDEPEND=" + ${DEPEND} + dev-python/pycparser[${PYTHON_USEDEP}] + dev-python/setuptools[${PYTHON_USEDEP}] +" +BDEPEND=" + ${RDEPEND} + virtual/pkgconfig + test? ( + dev-python/py[${PYTHON_USEDEP}] + ) +" + +distutils_enable_sphinx doc/source +distutils_enable_tests pytest + +PATCHES=( + "${FILESDIR}"/cffi-1.14.0-darwin-no-brew.patch +) + +src_prepare() { + if [[ ${CHOST} == *darwin* ]] ; then + # Don't obsessively try to find libffi + sed -i -e "s/.*\-iwithsysroot\/usr\/include\/ffi.*/\tpass/" setup.py || die + fi + distutils-r1_src_prepare +} + +src_configure() { + tc-export PKG_CONFIG +} + +python_test() { + local EPYTEST_IGNORE=( + # these tests call pip + testing/cffi0/test_zintegration.py + ) + + "${EPYTHON}" -c "import _cffi_backend as backend" || die + local -x PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 + epytest src/c testing +} diff --git a/sdk_container/src/third_party/portage-stable/dev-python/cffi/cffi-1.17.1.ebuild b/sdk_container/src/third_party/portage-stable/dev-python/cffi/cffi-1.17.1.ebuild new file mode 100644 index 00000000000..16efb4bcb9d --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/cffi/cffi-1.17.1.ebuild @@ -0,0 +1,71 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# please keep this ebuild at EAPI 8 -- sys-apps/portage dep +EAPI=8 + +DISTUTILS_EXT=1 +DISTUTILS_USE_PEP517=setuptools +# DO NOT ADD pypy to PYTHON_COMPAT +# pypy bundles a modified version of cffi. Use python_gen_cond_dep instead. +PYTHON_COMPAT=( python3_{10..13} ) + +inherit distutils-r1 toolchain-funcs pypi + +DESCRIPTION="Foreign Function Interface for Python calling C code" +HOMEPAGE=" + https://cffi.readthedocs.io/ + https://pypi.org/project/cffi/ +" + +LICENSE="MIT" +SLOT="0/${PV}" +KEYWORDS="~alpha amd64 ~arm ~arm64 ~hppa ~loong ~m68k ~mips ppc ppc64 ~riscv ~s390 sparc x86 ~amd64-linux ~x86-linux ~arm64-macos ~ppc-macos ~x64-macos ~x64-solaris" + +# Needs recent libffi for HPPA fixes +DEPEND=" + >=dev-libs/libffi-3.4.4-r1:= +" +# setuptools as a modern distutils provider +RDEPEND=" + ${DEPEND} + dev-python/pycparser[${PYTHON_USEDEP}] + dev-python/setuptools[${PYTHON_USEDEP}] +" +BDEPEND=" + ${RDEPEND} + virtual/pkgconfig + test? ( + dev-python/py[${PYTHON_USEDEP}] + ) +" + +distutils_enable_sphinx doc/source +distutils_enable_tests pytest + +PATCHES=( + "${FILESDIR}"/cffi-1.14.0-darwin-no-brew.patch +) + +src_prepare() { + if [[ ${CHOST} == *darwin* ]] ; then + # Don't obsessively try to find libffi + sed -i -e "s/.*\-iwithsysroot\/usr\/include\/ffi.*/\tpass/" setup.py || die + fi + distutils-r1_src_prepare +} + +src_configure() { + tc-export PKG_CONFIG +} + +python_test() { + local EPYTEST_IGNORE=( + # these tests call pip + testing/cffi0/test_zintegration.py + ) + + "${EPYTHON}" -c "import _cffi_backend as backend" || die + local -x PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 + epytest src/c testing +} diff --git a/sdk_container/src/third_party/portage-stable/dev-python/cffi/files/cffi-1.14.0-darwin-no-brew.patch b/sdk_container/src/third_party/portage-stable/dev-python/cffi/files/cffi-1.14.0-darwin-no-brew.patch new file mode 100644 index 00000000000..c92b6112b85 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/cffi/files/cffi-1.14.0-darwin-no-brew.patch @@ -0,0 +1,14 @@ +diff --git a/setup.py b/setup.py +index e1dd39d..3e88f74 100644 +--- a/setup.py ++++ b/setup.py +@@ -105,9 +105,6 @@ def uses_msvc(): + return config.try_compile('#ifndef _MSC_VER\n#error "not MSVC"\n#endif') + + def use_pkg_config(): +- if sys.platform == 'darwin' and os.path.exists('/usr/local/bin/brew'): +- use_homebrew_for_libffi() +- + _ask_pkg_config(include_dirs, '--cflags-only-I', '-I', sysroot=True) + _ask_pkg_config(extra_compile_args, '--cflags-only-other') + _ask_pkg_config(library_dirs, '--libs-only-L', '-L', sysroot=True) diff --git a/sdk_container/src/third_party/portage-stable/dev-python/cffi/metadata.xml b/sdk_container/src/third_party/portage-stable/dev-python/cffi/metadata.xml new file mode 100644 index 00000000000..6480813148b --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/cffi/metadata.xml @@ -0,0 +1,12 @@ + + + + + python@gentoo.org + Python + + + cffi + python-cffi/cffi + + diff --git a/sdk_container/src/third_party/portage-stable/dev-python/cryptography/Manifest b/sdk_container/src/third_party/portage-stable/dev-python/cryptography/Manifest new file mode 100644 index 00000000000..b2ad6633201 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/cryptography/Manifest @@ -0,0 +1,37 @@ +DIST asn1-0.16.2.crate 36082 BLAKE2B 70214556c18ddc9e31f58a1b5c59b5ef5e74f3662ec515b739bca66ac6272ffce258d8a73eed913aed0bb871aabff7a0c95e88853551292ae8f1425e8087d751 SHA512 518481d1bb12d95c1340e374e7b1bf23f550712ee57bb166e7892118ac9b602006a461605f9ebf1b7d60dfb70266229b87833827c5fd018361c33bd9a89e5e7b +DIST asn1_derive-0.16.2.crate 6099 BLAKE2B 709e2c3c1b698e5f9101bc56434bb7abff8a857fded1bda3552d1dc138fe8e88af6afc1e1b604a3acd877858f21e27c80c96d274330db4514f7bf375be5bac3e SHA512 d59670896090d048f2d739aeaa897638d91f211534400d7f102672d40ae887a2a5f4cc4ac61381c17c2d1388a18991736f6fe7fe2b50838b88f25017656e43bc +DIST autocfg-1.3.0.crate 16524 BLAKE2B 7d5a03853d6b4f0da08d8e139fb200da21e47fa7e50d1956270d0ff0cc496f660f8f800122c95eee9ba98d9210ab200c3010b782097483d12d6be4ac0df0e7c9 SHA512 a5570b955d57a7183ba148b335837dc5af24b202e80681027536d33fe2822509ba644fc70c29f018c893285ced2bf6774f44ca6c59f7c7e2226d5349cf7c3635 +DIST base64-0.22.1.crate 81597 BLAKE2B 6f216a560bd36e6e6b74e908344b457594cc768d9763070e269b56a14b150cbfc4b7f599d4c2a0a5f783638170ee132f0796fefb14fcac7fd73c58db0791007a SHA512 91cf2e4e7fc8815f9b8a86a7fa722a20eee3dc1dd57111b29e420de87ce7836bcdb1db01d3cafb9a977710ef63e7cc41b7772762323e68e0e832156858aace20 +DIST bitflags-2.6.0.crate 45357 BLAKE2B 3a368bd2eb58c095b7b4a46680cc2d90a28e24b2e37c854bbf8647c861c4b8fb37eca827599673c5c7df763048149dd82123d1ede1f8a0e58a6bc23c8250f7e6 SHA512 f9bb3c48931ed7e7e05ec6d13305af5da6b6c18861ff307d7dc17c658f63972c87b70b0527287b3625c8592befc207cfe15550654995faf3862bb12a6d95bacf +DIST cc-1.1.6.crate 81585 BLAKE2B 412ef9d62c32a42164f8c2b827c10f0d41e75faa77e6d1dd8515ff5ec43abd1da75bbb400460a43a252c93dd0a597c2e44c8e899a376d963f0d3727db7ca2c24 SHA512 ea8bd8150042268092360e6396226ee5e83ba154eae99d299c897ed16e8543fcfe3179e22b50b0497bcf065a16933f4ebf7edcae7e6fc8be3788f0ae7f61c000 +DIST cfg-if-1.0.0.crate 7934 BLAKE2B e99a5589c11d79d77a4537b34ce0a45d37b981c123b79b807cea836c89fc3926d693458893baca2882448d3d44e3f64e06141f6d916b748daa10b8cc1ae16d1b SHA512 0fb16a8882fd30e86b62c5143b1cb18ab564e84e75bd1f28fd12f24ffdc4a42e0d2e012a99abb606c12efe3c11061ff5bf8e24ab053e550ae083f7d90f6576ff +DIST cryptography-43.0.0.tar.gz 686873 BLAKE2B 09e1f73ed47a3ab03b49e6a65eceb0ee506b4e1c50b44cd0f971243159b27ea5f725350fcf2c702945438545a89d96ec026441b6b6151a9022bd61b926ca26cd SHA512 0a93a217bf09afca32df5ed6792b8e9de210ca4143697b8b97aa2c41b8e8382ffdce1bae47bf51a6319f03d9ec70933218030ab21d642a0ef907cac3e816929c +DIST cryptography-43.0.1.tar.gz 686927 BLAKE2B 5abc6fd0f06fdca735455c812b089f864457c379ae9a4d646b0a5633285be692e1b17eab0ec50e99b41d1c1238a4f81a4b2b0801777e8e41e25a4faa9285af15 SHA512 db33cc8930492ccdf1aa6466026e4a3ab50382c863fa2c3c454a554cd53f74592e06fb021b2bd6bc16981c8230089c7a076a352a9d7d982a824ef4c7b1895414 +DIST cryptography_vectors-43.0.0.tar.gz 35306242 BLAKE2B d1dceec0dbe02ad500c73bd94791c6b47320534268cc4fffdb799a632f37b27bd3de837a725c79f733f86eda813a1a512778615c62144275ca5e7aaaa3d65d08 SHA512 ca5221a390ebea4eda5d72f9ac9632849ce2174db51385405b1b41b702c0dcd2f24f7fbfaa027bb6eb8c63588ac1eae5fdc7978a08c1561dcaaaaa998b67eaef +DIST cryptography_vectors-43.0.1.tar.gz 35306252 BLAKE2B 0ff68e6c1088656491e474f8770f61c0a2c45a318e565325c9259ffd938a765ea9306f13ba25d5e2097d7d113d8a4556914aa07e016ee90ae78d7157cf6d5e6a SHA512 934c4fadba915b10f3216c08cdb862968d138a40c0a3ea2aed6605685730d1d2b60767660356236b519ff98d52c2f21bf9ead4bc247eab80db27257d671037f2 +DIST foreign-types-0.3.2.crate 7504 BLAKE2B 520818b702d990d296ecd31a8646850202509ccfa18edd0e1b260289619a6c351e758f317ec0824bd76eccb209b6f087057c25f1bd01a47897715013dd834867 SHA512 bf27b8243ed482c202d120383374f19ff09422535e24b9c1aebccc66529bf300ca17b8bbc76d67f98ac092e614497afe3add9dc68aa69c93074df05762f91232 +DIST foreign-types-shared-0.1.1.crate 5672 BLAKE2B d2e42e04b6657e7a69fe0bd20c672176629c743e49a55fd007bb30e289710b70045d445ae9cae0eeaa747ee708c90e8abd9b5fc39bad8ec0666befe1b696d4f1 SHA512 bafdb2143e136fb0818e2ffd90b5c862b7181647d6568947d4e4531012bbf7a57b597221ec7056c1b562dfc0c3b5dead26d1a4111ebc15e7863737a873518a4a +DIST heck-0.5.0.crate 11517 BLAKE2B 5365ec43b2239a76b33a174f1a4292ece4147f9d382a68c6c60db78fdc8bad0afb1d51a65bcb25e96675372faa4ea37c318265030b0546ba51942f7c929e1835 SHA512 f044fc9c3d22466629fd8f772ec0555350fd611c0cfadca51d99a3d2f10e155f77c1091916c8a95a6b9b499f366c2e99a5fbf45b010f988bfb9b2501bf9f6a76 +DIST indoc-2.0.5.crate 14396 BLAKE2B fe838c6a855d6ff7396675a3fe9b2e0b06a93cfd4013b0b843d24d2fb81f6566528bfd1753c649646f06cb7e59262bd6ec3ed79d4e6f01d740cf0682355f2e5a SHA512 095fb56a3d87946c42a63065a8b276c2d4b9b835800014b400bb987593bf56701bad9f55d947f090740fdb7641a4f3c87fe8bfa5724709e95254d1e8e2e3616f +DIST libc-0.2.155.crate 743539 BLAKE2B 42cdcf8d4a187383548b1f09d404474f168916d626d614463fe10a1fd886e972e1caf6297e75445214af3f31fe631d0927e54ec1cdc63e20082b3587e38dce16 SHA512 05354bba532b8338bda1f88f12c7f3893429734a06e33925fca2b99d49548ae5216e2cd84e782d2368a2dfef20b0e035e2dcad8dd13ede7119462a8c639b2807 +DIST memoffset-0.9.1.crate 9032 BLAKE2B 0aab55fe084134bb599c52d77c96400db40949b1013e7037747ada4fcec8dc4a124b6f3755f04b36e057eb2fb4a6bd6f07d6eebcf166f8a71405ef434d802fbf SHA512 3a236c0f481e36973b9f805e454c2efe4dd375e6b4ee406b57145136c70d5fbf4e1183d563ebf3b5fbde7363bbf5f08f0d88e507aae5bda4cc75664ecd0e33aa +DIST once_cell-1.19.0.crate 33046 BLAKE2B c14b374eaf4ac0f60acc2e02f7bba270a0e8e0a6978d749cd3cb0ab3eb26907e4fbea70dd5132982f90290381ed18ff8a87fd530f1415fabffac864f157ea380 SHA512 4154876afd34a699ee650d1a8a1c5ee5a25f0ebd9388b8bef2564e33629fae68f113d7507488c68abbe7ea1acf9bbc41813cbbf3ef3e464e3f3b9cc7a51d870c +DIST openssl-0.10.66.crate 273705 BLAKE2B 7892e96dac3b24ad5622833b4061bd82028210f9f26ec9772cebb65905ff6e45da8b21ad1aabfb87bb5610f534018da6bd20c10eaee8c189dd08a7ebfbf12b4b SHA512 2f4dd6e40dd8aff8c04563517fabeecd5ac0d986764649cc9af9bf4ce25757a67f75655eee207703b46fe57661a216ff00144358ffcbc70525447a063fa086c1 +DIST openssl-macros-0.1.1.crate 5601 BLAKE2B 69dc1c1f3b7bc4f934cae0dce64c3efa501162e5279efd6af3b74f7a7716c04b6996b306b310f1c045cfa2eff2895314a47ecbb020a817e461c6d77d0bc11e92 SHA512 57e75c84f78fb83f884eeaedb0dd135ecb40192dad2facd908e6a575c9b65b38a2c93bca4630e09ea5a82c77d8bc8364cb2f5778cbfe9d8f484cafe3346b883c +DIST openssl-sys-0.9.103.crate 71552 BLAKE2B 4cc1ab93f5a444b4b985c84f6ae90f345da4639e4ff7c5502dc1ae59f842d46e3855057a7c05855f7cd739b5311f330dff361480ef2a0102fe46471506956148 SHA512 61b802f6baf918ec055be90ee47c69fe0184f6d9a1d29c748386192a11d4df115758961ec9b636126a6b42d7d8f7509248c59f7c035905558c4cc35b804a8eaf +DIST pem-3.0.4.crate 13040 BLAKE2B 33126cd0feeeeb8b57691c50f6535c43e853b9835308d69a5afb426c7a738d260a67d5c46f091ad73e934f0347d976c6f65f88b2f7b1058eca542296191bcb9a SHA512 be743157e11ed76e5a9a60f5e58f50277910ecbf12df492b114b4211f1f1d69555702d955337ec41d368566ae1697f550e3705a195105068c617b9392c43f56d +DIST pkg-config-0.3.30.crate 20613 BLAKE2B e14dd544612f74b038bc7d279d629034237946c261e3e97621d6ac910a12f4fa4e75932dbd5d3339e62325d0ccf33002b07f04b0523f93d2bd3b1a919841ba66 SHA512 e4bce232e1e1cbb17d1c08c3de4dd12613f5a5238f831c2a765b6ede9b494e647d2416a7d9a0c926104e24066dd1b38df8df98a6c55d62f25060f80eb33d064d +DIST portable-atomic-1.7.0.crate 145385 BLAKE2B 7d9622d636677e3adae0f909405090318a9d6189fc18683ed21074e9360f213b44c5213f3561e3dd1f642547c2c2e6682b9e1efa63243c1f12636bb11bd15dbe SHA512 0849edaa7a1f9ea66182443e31691e7839c857240916521bbd6009b5e692b13f5b315df36e656134651386bc50d895ecf6155a906750009514cad8bfc7e57fe2 +DIST proc-macro2-1.0.86.crate 48958 BLAKE2B 4b89e07f23af8328dbb34fe2b3f1b202f1e6a3885a6269740a23359b41bb4099ac2484565d3b2b0936261689ca525785ac620c766997234fd8d0f409e80e5ea3 SHA512 1cdb7e22a35ae231d880c9420784c9acf97bda2db258b3d34aae5061dc1858449defe19a49e12c6a4173906aa72a4115059ac2db0fc760205fd2ab8b5b414434 +DIST pyo3-0.22.2.crate 538342 BLAKE2B faf347695117f9fe0ebe5cd7f6aa1b0dcfe718343875d6c06438046deccc1075f104d2a2413dcda41ae9827bc363aa147057b45968f6634f577a6a4510a4bb8e SHA512 e8bae09059f50ffe477dad44499cedeaf3a734665f0fd8e8bd4b44f48578d21e4bdb8d55ceea00c5a27da750761842ddf89cfcecdecb2e7a4a17ab192259be9c +DIST pyo3-build-config-0.22.2.crate 31225 BLAKE2B c2e6a3d3d23b7f2f51bcbf1214ab20a298a1e62f85c9af3dab1e77b09f20b657b576feefffb18eb49d438f0ffab525b6bcd1086d500601c327ffd4fd24a719ee SHA512 644c82d30bb27051557efcc9789a81380a64e29bc62abf97de88f42c3791dac74228c7a7d09e0d46d14f07c0475f0bc03fac6ed1367b9a616153e8820b94cbc8 +DIST pyo3-ffi-0.22.2.crate 67749 BLAKE2B 0a4357d5f4fbcab9717d58b7a80b63a63bc329267d4725136c4eac7c0101095a50e5f840638dde79034e5df99c4f46664cfdc2ad437837643db5d475c5705cb3 SHA512 bf8b83b4790832d99de8c6a61a15a43fc189505dd843011933305f7f93c4f5f4849fb00cc2a6fa410b788645f8ed8c0df61799cf801966a925abb9756b1ab579 +DIST pyo3-macros-0.22.2.crate 8136 BLAKE2B 9dc97d2f60581db1b8ddb562dac917069525f297fe2cbb9aff3ed34d5a08ea43c112c9c7a450539da3536d753778b5ca506dd1b18e1d6b8a3649fc098e7af439 SHA512 f4f4f6af8dc3aa4bcc1698661990ab2112391ef9502e9f71d86e35bd10dc4e1be309102ebb1b7b32751817a6033168dc0486fdb16b35c626101e69f0de807a4a +DIST pyo3-macros-backend-0.22.2.crate 65620 BLAKE2B 37fba9ff384373418d3a7341acafb8e33308a64e30026f828693a37c32ab4a74d058f2db84d00467a20f9f267c96fe54c0f154d1ebbae92490e8dfc0d29c042f SHA512 0517080c0d5d4ed8136521fd37aa3a192c2eb8cab58545d8543ee4df9cd0dcea19fe0678d5ab90f05fe3eb0f4a86fc2f07b76f2e12ac1fcf7e7c195c2ffa4fd8 +DIST quote-1.0.36.crate 28507 BLAKE2B b93495163ed205e33543ed45f084870240d479071d643704b6e348fb9ada6e1d8401893c13348b9964f4b6b17ddb96cb5458eec540f0d761655fcb96a4cd9129 SHA512 f1f002a912692f7ffd4912ca980ec57ff4aca3a7d9e2e42e9e3409e2105c9f59d86c05719f6af309bccaef2f8843b0848a6e3afda3356e045d8e7cc5956ae685 +DIST self_cell-1.0.4.crate 15220 BLAKE2B 9a617058652ab2a2e92434b6eef58a813ce0be5afed9525c4d4c819c25c7cd87aaa12d129c8c4ca9d74c3ea33d81e9dd295f121887070364185b9ab33021544c SHA512 042467e5f3ac0305e2a634df0b9a9379e92b54813e05c3a7652d5327a4a9a784f49e897c968c5c7a87017284d42a889b5420ad18e97ea84183e0283a46dc907a +DIST syn-2.0.71.crate 266398 BLAKE2B 78760c9965b59e14ab5d97e83c4dabdba99cd1933b66350c7d5c5f9e55f34fe68207597b51aeb023b211a065d986889655ab701b94347397ca6856a4fcbcdc85 SHA512 cf6264bc148ec550d943d7d146c7360a7d753e37ef553e6d0c6dc265bf516084530a5617f6826069275cc6f71d9f820014f7d92f04356ae964df8b79edaf7bbe +DIST target-lexicon-0.12.15.crate 26384 BLAKE2B d1ba50aa9d50647c6f778df86b35db1a4dee56fad918e6ef216688d9ac716dc5e8b40bff15aa89a99e4874e74d7e2731ad7fd9ea7094652def8abf57b74f9811 SHA512 32cf3e2da1c28003e1b6347abc8ae4d8182bf5b719ef84772271fc871dbaf96ec98c03b555a748cb8ab76584e67e17532757193d1d84b057cc90bed525727fb3 +DIST unicode-ident-1.0.12.crate 42168 BLAKE2B 4cede03c08758ccd6bf53a0d0057d7542dfdd0c93d342e89f3b90460be85518a9fd24958d8b1da2b5a09b5ddbee8a4263982194158e171c2bba3e394d88d6dac SHA512 bc1824e1e4452a40732fc69874d7e1a66f7803717a314790dcf48867eba34bc9441331ef031e386912e52c385645c25b6ed39d4f149973b5b97371b1b96b1920 +DIST unindent-0.2.3.crate 7306 BLAKE2B a57407b117e99c230750c7d4a2a0899586c8271e4ba88ecb409c976905c014f42885372c234a75fbfbedf71dbed779f95f735975d150adacdcb61152a49db4c2 SHA512 2f1eb420ea3653b00d3e5fa0c2c105da8fd8a37cb3e699373c168604b799fccd5f0faf0cddce4212d119c2afb0c86b41efc3a50752b83ff7beda2bd84d360505 +DIST vcpkg-0.2.15.crate 228735 BLAKE2B 6b6bacd9a7fa38919241f45a97f58cae957e58d3aac99df208a26aa718e4f1644f4ccefa31b09151e5c1952288e0e5837c363918b98c7f55079a948a952c1c50 SHA512 7322a21e8811b2fe4e79e09dc321458068ecdf1953f05d36233f3278ecc0b1dfc64194db7010dd46fcf692285f42475beb090c6c6cac0c8f9fe0eb5c770e3172 diff --git a/sdk_container/src/third_party/portage-stable/dev-python/cryptography/cryptography-43.0.0.ebuild b/sdk_container/src/third_party/portage-stable/dev-python/cryptography/cryptography-43.0.0.ebuild new file mode 100644 index 00000000000..1eb56d3e3e5 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/cryptography/cryptography-43.0.0.ebuild @@ -0,0 +1,139 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +CARGO_OPTIONAL=yes +DISTUTILS_EXT=1 +DISTUTILS_USE_PEP517=maturin +PYTHON_COMPAT=( python3_{10..13} pypy3 ) +PYTHON_REQ_USE="threads(+)" + +CRATES=" + asn1@0.16.2 + asn1_derive@0.16.2 + autocfg@1.3.0 + base64@0.22.1 + bitflags@2.6.0 + cc@1.1.6 + cfg-if@1.0.0 + foreign-types-shared@0.1.1 + foreign-types@0.3.2 + heck@0.5.0 + indoc@2.0.5 + libc@0.2.155 + memoffset@0.9.1 + once_cell@1.19.0 + openssl-macros@0.1.1 + openssl-sys@0.9.103 + openssl@0.10.66 + pem@3.0.4 + pkg-config@0.3.30 + portable-atomic@1.7.0 + proc-macro2@1.0.86 + pyo3-build-config@0.22.2 + pyo3-ffi@0.22.2 + pyo3-macros-backend@0.22.2 + pyo3-macros@0.22.2 + pyo3@0.22.2 + quote@1.0.36 + self_cell@1.0.4 + syn@2.0.71 + target-lexicon@0.12.15 + unicode-ident@1.0.12 + unindent@0.2.3 + vcpkg@0.2.15 +" + +inherit cargo distutils-r1 flag-o-matic multiprocessing pypi + +VEC_P=cryptography_vectors-$(ver_cut 1-3) +DESCRIPTION="Library providing cryptographic recipes and primitives" +HOMEPAGE=" + https://github.com/pyca/cryptography/ + https://pypi.org/project/cryptography/ +" +SRC_URI+=" + ${CARGO_CRATE_URIS} + test? ( + $(pypi_sdist_url cryptography_vectors "$(ver_cut 1-3)") + ) +" + +LICENSE="|| ( Apache-2.0 BSD ) PSF-2" +# Dependent crate licenses +LICENSE+=" + Apache-2.0 Apache-2.0-with-LLVM-exceptions BSD MIT Unicode-DFS-2016 +" +SLOT="0" +KEYWORDS="amd64 arm arm64 ~loong ~mips ppc ppc64 ~riscv ~s390 sparc x86" + +RDEPEND=" + >=dev-libs/openssl-1.0.2o-r6:0= + $(python_gen_cond_dep ' + >=dev-python/cffi-1.8:=[${PYTHON_USEDEP}] + ' 'python*') +" +DEPEND=" + ${RDEPEND} +" +# XXX: Drop explicit >=virtual/rust-1.56.0 dep once that's the minimum in cargo.eclass +# and replace it with ${RUST_DEPEND} +BDEPEND=" + dev-python/setuptools[${PYTHON_USEDEP}] + >=virtual/rust-1.56.0 + test? ( + dev-python/certifi[${PYTHON_USEDEP}] + >=dev-python/hypothesis-1.11.4[${PYTHON_USEDEP}] + dev-python/iso8601[${PYTHON_USEDEP}] + dev-python/pretend[${PYTHON_USEDEP}] + dev-python/pyasn1-modules[${PYTHON_USEDEP}] + dev-python/pytest-subtests[${PYTHON_USEDEP}] + dev-python/pytest-xdist[${PYTHON_USEDEP}] + dev-python/pytz[${PYTHON_USEDEP}] + ) +" + +# Files built without CFLAGS/LDFLAGS, acceptable for rust +QA_FLAGS_IGNORED="usr/lib.*/py.*/site-packages/cryptography/hazmat/bindings/_rust.*.so" + +distutils_enable_tests pytest + +src_unpack() { + cargo_src_unpack +} + +src_prepare() { + local PATCHES=( + # https://github.com/pyca/cryptography/pull/11324 + "${FILESDIR}/${P}-rust-openssl-crash.patch" + ) + + default + + sed -i -e 's:--benchmark-disable::' pyproject.toml || die + + # work around availability macros not supported in GCC (yet) + if [[ ${CHOST} == *-darwin* ]] ; then + local darwinok=0 + if [[ ${CHOST##*-darwin} -ge 16 ]] ; then + darwinok=1 + fi + sed -i -e 's/__builtin_available(macOS 10\.12, \*)/'"${darwinok}"'/' \ + src/_cffi_src/openssl/src/osrandom_engine.c || die + fi +} + +python_configure_all() { + filter-lto # bug #903908 + + export UNSAFE_PYO3_SKIP_VERSION_CHECK=1 +} + +python_test() { + local -x PYTHONPATH="${PYTHONPATH}:${WORKDIR}/cryptography_vectors-${PV}" + local EPYTEST_IGNORE=( + tests/bench + ) + epytest -n "$(makeopts_jobs)" +} diff --git a/sdk_container/src/third_party/portage-stable/dev-python/cryptography/cryptography-43.0.1.ebuild b/sdk_container/src/third_party/portage-stable/dev-python/cryptography/cryptography-43.0.1.ebuild new file mode 100644 index 00000000000..110e22b8718 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/cryptography/cryptography-43.0.1.ebuild @@ -0,0 +1,134 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +CARGO_OPTIONAL=yes +DISTUTILS_EXT=1 +DISTUTILS_USE_PEP517=maturin +PYTHON_COMPAT=( python3_{10..13} pypy3 ) +PYTHON_REQ_USE="threads(+)" + +CRATES=" + asn1@0.16.2 + asn1_derive@0.16.2 + autocfg@1.3.0 + base64@0.22.1 + bitflags@2.6.0 + cc@1.1.6 + cfg-if@1.0.0 + foreign-types-shared@0.1.1 + foreign-types@0.3.2 + heck@0.5.0 + indoc@2.0.5 + libc@0.2.155 + memoffset@0.9.1 + once_cell@1.19.0 + openssl-macros@0.1.1 + openssl-sys@0.9.103 + openssl@0.10.66 + pem@3.0.4 + pkg-config@0.3.30 + portable-atomic@1.7.0 + proc-macro2@1.0.86 + pyo3-build-config@0.22.2 + pyo3-ffi@0.22.2 + pyo3-macros-backend@0.22.2 + pyo3-macros@0.22.2 + pyo3@0.22.2 + quote@1.0.36 + self_cell@1.0.4 + syn@2.0.71 + target-lexicon@0.12.15 + unicode-ident@1.0.12 + unindent@0.2.3 + vcpkg@0.2.15 +" + +inherit cargo distutils-r1 flag-o-matic multiprocessing pypi + +VEC_P=cryptography_vectors-$(ver_cut 1-3) +DESCRIPTION="Library providing cryptographic recipes and primitives" +HOMEPAGE=" + https://github.com/pyca/cryptography/ + https://pypi.org/project/cryptography/ +" +SRC_URI+=" + ${CARGO_CRATE_URIS} + test? ( + $(pypi_sdist_url cryptography_vectors "$(ver_cut 1-3)") + ) +" + +LICENSE="|| ( Apache-2.0 BSD ) PSF-2" +# Dependent crate licenses +LICENSE+=" + Apache-2.0 Apache-2.0-with-LLVM-exceptions BSD MIT Unicode-DFS-2016 +" +SLOT="0" +KEYWORDS="amd64 ~arm ~arm64 ~loong ~mips ~ppc ppc64 ~riscv ~s390 sparc x86" + +RDEPEND=" + >=dev-libs/openssl-1.0.2o-r6:0= + $(python_gen_cond_dep ' + >=dev-python/cffi-1.8:=[${PYTHON_USEDEP}] + ' 'python*') +" +DEPEND=" + ${RDEPEND} +" +# XXX: Drop explicit >=virtual/rust-1.56.0 dep once that's the minimum in cargo.eclass +# and replace it with ${RUST_DEPEND} +BDEPEND=" + dev-python/setuptools[${PYTHON_USEDEP}] + >=virtual/rust-1.56.0 + test? ( + dev-python/certifi[${PYTHON_USEDEP}] + >=dev-python/hypothesis-1.11.4[${PYTHON_USEDEP}] + dev-python/iso8601[${PYTHON_USEDEP}] + dev-python/pretend[${PYTHON_USEDEP}] + dev-python/pyasn1-modules[${PYTHON_USEDEP}] + dev-python/pytest-subtests[${PYTHON_USEDEP}] + dev-python/pytest-xdist[${PYTHON_USEDEP}] + dev-python/pytz[${PYTHON_USEDEP}] + ) +" + +# Files built without CFLAGS/LDFLAGS, acceptable for rust +QA_FLAGS_IGNORED="usr/lib.*/py.*/site-packages/cryptography/hazmat/bindings/_rust.*.so" + +distutils_enable_tests pytest + +src_unpack() { + cargo_src_unpack +} + +src_prepare() { + default + + sed -i -e 's:--benchmark-disable::' pyproject.toml || die + + # work around availability macros not supported in GCC (yet) + if [[ ${CHOST} == *-darwin* ]] ; then + local darwinok=0 + if [[ ${CHOST##*-darwin} -ge 16 ]] ; then + darwinok=1 + fi + sed -i -e 's/__builtin_available(macOS 10\.12, \*)/'"${darwinok}"'/' \ + src/_cffi_src/openssl/src/osrandom_engine.c || die + fi +} + +python_configure_all() { + filter-lto # bug #903908 + + export UNSAFE_PYO3_SKIP_VERSION_CHECK=1 +} + +python_test() { + local -x PYTHONPATH="${PYTHONPATH}:${WORKDIR}/cryptography_vectors-${PV}" + local EPYTEST_IGNORE=( + tests/bench + ) + epytest -n "$(makeopts_jobs)" +} diff --git a/sdk_container/src/third_party/portage-stable/dev-python/cryptography/files/cryptography-43.0.0-rust-openssl-crash.patch b/sdk_container/src/third_party/portage-stable/dev-python/cryptography/files/cryptography-43.0.0-rust-openssl-crash.patch new file mode 100644 index 00000000000..74d2e1c9229 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/cryptography/files/cryptography-43.0.0-rust-openssl-crash.patch @@ -0,0 +1,79 @@ +From ef3578980ed117feb5e1b4c7a1f8c68efcdc066e Mon Sep 17 00:00:00 2001 +From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> +Date: Sun, 21 Jul 2024 16:36:43 +0000 +Subject: [PATCH] Bump openssl from 0.10.65 to 0.10.66 in /src/rust (#11320) + +Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.65 to 0.10.66. +- [Release notes](https://github.com/sfackler/rust-openssl/releases) +- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.65...openssl-v0.10.66) + +--- +updated-dependencies: +- dependency-name: openssl + dependency-type: direct:production + update-type: version-update:semver-patch +... + +Signed-off-by: dependabot[bot] +Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> +--- + src/rust/Cargo.lock | 4 ++-- + src/rust/Cargo.toml | 2 +- + src/rust/cryptography-key-parsing/Cargo.toml | 2 +- + src/rust/cryptography-openssl/Cargo.toml | 2 +- + 4 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock +index fe3398f25393..c5a020fc8f10 100644 +--- a/src/rust/Cargo.lock ++++ b/src/rust/Cargo.lock +@@ -179,9 +179,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + + [[package]] + name = "openssl" +-version = "0.10.65" ++version = "0.10.66" + source = "registry+https://github.com/rust-lang/crates.io-index" +-checksum = "c2823eb4c6453ed64055057ea8bd416eda38c71018723869dd043a3b1186115e" ++checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" + dependencies = [ + "bitflags", + "cfg-if", +diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml +index d58ee9e7ec28..4a91705de96c 100644 +--- a/src/rust/Cargo.toml ++++ b/src/rust/Cargo.toml +@@ -26,7 +26,7 @@ cryptography-x509 = { path = "cryptography-x509" } + cryptography-x509-verification = { path = "cryptography-x509-verification" } + cryptography-openssl = { path = "cryptography-openssl" } + pem = { version = "3", default-features = false } +-openssl = "0.10.65" ++openssl = "0.10.66" + openssl-sys = "0.9.103" + foreign-types-shared = "0.1" + self_cell = "1" +diff --git a/src/rust/cryptography-key-parsing/Cargo.toml b/src/rust/cryptography-key-parsing/Cargo.toml +index d1f945f961a0..e88e3bc9e691 100644 +--- a/src/rust/cryptography-key-parsing/Cargo.toml ++++ b/src/rust/cryptography-key-parsing/Cargo.toml +@@ -9,6 +9,6 @@ rust-version.workspace = true + [dependencies] + asn1 = { version = "0.16.2", default-features = false } + cfg-if = "1" +-openssl = "0.10.65" ++openssl = "0.10.66" + openssl-sys = "0.9.103" + cryptography-x509 = { path = "../cryptography-x509" } +diff --git a/src/rust/cryptography-openssl/Cargo.toml b/src/rust/cryptography-openssl/Cargo.toml +index c0f3f5d72ce1..f340ed87cf53 100644 +--- a/src/rust/cryptography-openssl/Cargo.toml ++++ b/src/rust/cryptography-openssl/Cargo.toml +@@ -8,7 +8,7 @@ rust-version.workspace = true + + [dependencies] + cfg-if = "1" +-openssl = "0.10.65" ++openssl = "0.10.66" + ffi = { package = "openssl-sys", version = "0.9.101" } + foreign-types = "0.3" + foreign-types-shared = "0.1" diff --git a/sdk_container/src/third_party/portage-stable/dev-python/cryptography/metadata.xml b/sdk_container/src/third_party/portage-stable/dev-python/cryptography/metadata.xml new file mode 100644 index 00000000000..e334e10a978 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/cryptography/metadata.xml @@ -0,0 +1,13 @@ + + + + + python@gentoo.org + Python + + + cpe:/a:cryptography_project:cryptography + cryptography + pyca/cryptography + + diff --git a/sdk_container/src/third_party/portage-stable/dev-python/pefile/Manifest b/sdk_container/src/third_party/portage-stable/dev-python/pefile/Manifest new file mode 100644 index 00000000000..52fba18aab9 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/pefile/Manifest @@ -0,0 +1 @@ +DIST pefile-2024.8.26.gh.tar.gz 76008 BLAKE2B 7f21d07bbe9a08239739f589e35d0ef4b5172e26b2a90acdbedc7792be70fdb0d4ee01888d674384fb011f3c716406c1b1a23b29fa412ce01863cae89acbc4bc SHA512 62781f2ab84040a13304ce550dd1e943991df152c5f2951281906e837b1659694051a074ff49cd08d5d508e9b70009b56418a4237511c4464c4eba9bda4bccf7 diff --git a/sdk_container/src/third_party/portage-stable/dev-python/pefile/metadata.xml b/sdk_container/src/third_party/portage-stable/dev-python/pefile/metadata.xml new file mode 100644 index 00000000000..a8d16bad599 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/pefile/metadata.xml @@ -0,0 +1,22 @@ + + + + + mario.haustein@hrz.tu-chemnitz.de + Mario Haustein + + + sam@gentoo.org + Sam James + + + pefile is a multi-platform Python module to parse and work with + Portable Executable (PE) files. Most of the information contained in + the PE file headers is accessible, as well as all the sections' details + and data. + + + erocarrera/pefile + pefile + + diff --git a/sdk_container/src/third_party/portage-stable/dev-python/pefile/pefile-2024.8.26.ebuild b/sdk_container/src/third_party/portage-stable/dev-python/pefile/pefile-2024.8.26.ebuild new file mode 100644 index 00000000000..5e1d6ab44aa --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/pefile/pefile-2024.8.26.ebuild @@ -0,0 +1,27 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +DISTUTILS_USE_PEP517=setuptools +PYTHON_COMPAT=( python3_{10..13} ) +inherit distutils-r1 + +DESCRIPTION="Module to read and work with Portable Executable (PE) files" +HOMEPAGE="https://github.com/erocarrera/pefile" + +if [[ ${PV} == 9999 ]] ; then + EGIT_REPO_URI="https://github.com/erocarrera/pefile.git" + inherit git-r3 +else + SRC_URI="https://github.com/erocarrera/pefile/releases/download/v${PV}/${P}.tar.gz -> ${P}.gh.tar.gz" + KEYWORDS="amd64 arm arm64 ~loong ppc ppc64 ~riscv x86" +fi + +LICENSE="MIT" +SLOT="0" + +# Unfortunately there is nothing we can test here. Upstream doesn't ship a test +# suite inside the release files. The test fixtures in the source repo is +# encrypted so that only their CI pipeline is able to run the tests. +RESTRICT="test" diff --git a/sdk_container/src/third_party/portage-stable/dev-python/pefile/pefile-9999.ebuild b/sdk_container/src/third_party/portage-stable/dev-python/pefile/pefile-9999.ebuild new file mode 100644 index 00000000000..3eecccc699f --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/pefile/pefile-9999.ebuild @@ -0,0 +1,27 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +DISTUTILS_USE_PEP517=setuptools +PYTHON_COMPAT=( python3_{10..13} ) +inherit distutils-r1 + +DESCRIPTION="Module to read and work with Portable Executable (PE) files" +HOMEPAGE="https://github.com/erocarrera/pefile" + +if [[ ${PV} == 9999 ]] ; then + EGIT_REPO_URI="https://github.com/erocarrera/pefile.git" + inherit git-r3 +else + SRC_URI="https://github.com/erocarrera/pefile/releases/download/v${PV}/${P}.tar.gz -> ${P}.gh.tar.gz" + KEYWORDS="~amd64 ~arm ~arm64 ~loong ~ppc ~ppc64 ~riscv ~x86" +fi + +LICENSE="MIT" +SLOT="0" + +# Unfortunately there is nothing we can test here. Upstream doesn't ship a test +# suite inside the release files. The test fixtures in the source repo is +# encrypted so that only their CI pipeline is able to run the tests. +RESTRICT="test" diff --git a/sdk_container/src/third_party/portage-stable/dev-python/ply/Manifest b/sdk_container/src/third_party/portage-stable/dev-python/ply/Manifest new file mode 100644 index 00000000000..d70f495e3f4 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/ply/Manifest @@ -0,0 +1,2 @@ +DIST ply-3.11-py3.12-assert.patch.xz 3832 BLAKE2B 5872a2f6c71ee093dfcb12a3a9b80c54091ba2a3d331948ccd88918fd263569a413e87962c607368f23f79abefd0f98738f1e1a33413832983ff3057c1ea021b SHA512 bc145cef28a0947773ee13df4a86fd60b04ebe8a06e563059a32eff55475f54bb99fb7cf7ef73c463d92b8795013b7c9f1aebcdf5a6c4f98d71675710f496b97 +DIST ply-3.11.tar.gz 159130 BLAKE2B 58c50b9dad445ad83a64aaa8174ed4602b36f5c8df33a7d62590a92388c4a21c9800599c1d4e4db6f02630e8dee4c8482611e26498e4aa8ccdb2cf3453ae1db4 SHA512 37e39a4f930874933223be58a3da7f259e155b75135f1edd47069b3b40e5e96af883ebf1c8a1bbd32f914a9e92cfc12e29fec05cf61b518f46c1d37421b20008 diff --git a/sdk_container/src/third_party/portage-stable/dev-python/ply/files/3.6-picklefile-IOError.patch b/sdk_container/src/third_party/portage-stable/dev-python/ply/files/3.6-picklefile-IOError.patch new file mode 100644 index 00000000000..85b39494a6f --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/ply/files/3.6-picklefile-IOError.patch @@ -0,0 +1,24 @@ +From f50768b0b2176998675e728d84ac05f0eef19614 Mon Sep 17 00:00:00 2001 +From: Mike Gilbert +Date: Sun, 17 May 2015 12:14:16 -0400 +Subject: [PATCH] Catch/ignore IOError when opening picklefile for reading in + yacc.yacc() + +Should resolve #66. +--- + ply/yacc.py | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/ply/yacc.py b/ply/yacc.py +index eb02cc2..2835c90 100644 +--- a/ply/yacc.py ++++ b/ply/yacc.py +@@ -3265,6 +3265,8 @@ def yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, star + errorlog.warning(str(e)) + except ImportError: + pass ++ except IOError: ++ pass + + if debuglog is None: + if debug: diff --git a/sdk_container/src/third_party/portage-stable/dev-python/ply/metadata.xml b/sdk_container/src/third_party/portage-stable/dev-python/ply/metadata.xml new file mode 100644 index 00000000000..5cbef0a9f52 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/ply/metadata.xml @@ -0,0 +1,26 @@ + + + + + python@gentoo.org + Python + + +PLY is a Python-only implementation of the popular compiler construction +tools lex and yacc. The implementation borrows ideas from a number of +previous efforts; most notably John Aycock's SPARK toolkit. However, +the overall flavor of the implementation is more closely modeled after +the C version of lex and yacc. The other significant feature of PLY is +that it provides extensive input validation and error reporting--much +more so than other Python parsing tools. + + +PLYはLexとYaccの有名なコンパイラ・コンストラクション・ツールのPython言語実装です +。この実装は以前の試みから幾つものアイディアを借りています。そのほとんどがJohn AycockのSPARKツールキットからです。しかしながら、実装の全体像はC言語によるLexとYaccにより近いモデルです。PLYの他の重要点は幅広い入力バリデーションとエラー報告を提供する点です。 -- その二点は他のPython言語パーサーより優れています。 + + + + ply + dabeaz/ply + + diff --git a/sdk_container/src/third_party/portage-stable/dev-python/ply/ply-3.11-r2.ebuild b/sdk_container/src/third_party/portage-stable/dev-python/ply/ply-3.11-r2.ebuild new file mode 100644 index 00000000000..617cc4c1c42 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/ply/ply-3.11-r2.ebuild @@ -0,0 +1,47 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# please keep this ebuild at EAPI 7 -- sys-apps/portage dep +EAPI=7 + +DISTUTILS_USE_PEP517=setuptools +PYTHON_COMPAT=( python3_{10..13} pypy3 ) + +inherit distutils-r1 pypi + +DESCRIPTION="Python Lex-Yacc library" +HOMEPAGE=" + http://www.dabeaz.com/ply/ + https://github.com/dabeaz/ply/ + https://pypi.org/project/ply/ +" +SRC_URI+=" https://dev.gentoo.org/~sam/distfiles/${CATEGORY}/${PN}/${P}-py3.12-assert.patch.xz" + +LICENSE="BSD" +SLOT="0/${PV}" +KEYWORDS="~alpha amd64 arm arm64 hppa ~loong ~m68k ~mips ppc ppc64 ~riscv ~s390 sparc x86 ~amd64-linux ~x86-linux ~arm64-macos ~ppc-macos ~x64-macos ~x64-solaris" +IUSE="examples" + +DOCS=( ANNOUNCE CHANGES TODO ) + +PATCHES=( + "${FILESDIR}/3.6-picklefile-IOError.patch" + "${WORKDIR}/${P}-py3.12-assert.patch" +) + +python_test() { + # Checks for pyc/pyo files + local -x PYTHONDONTWRITEBYTECODE= + + cd test || die + local t + for t in testlex.py testyacc.py; do + "${EPYTHON}" "${t}" -v || die "${t} fails with ${EPYTHON}" + done +} + +python_install_all() { + local HTML_DOCS=( doc/. ) + use examples && dodoc -r example + distutils-r1_python_install_all +} diff --git a/sdk_container/src/third_party/portage-stable/dev-python/pycparser/Manifest b/sdk_container/src/third_party/portage-stable/dev-python/pycparser/Manifest new file mode 100644 index 00000000000..92399af68de --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/pycparser/Manifest @@ -0,0 +1 @@ +DIST pycparser-2.22.tar.gz 172736 BLAKE2B a080df68cf114c355949b2911a80e89ed02a64b8d1d03e3c5807222249e5dfd2491f691962885dbadcdaf323b55a05c5597319ac082dcf6c67a9ac952be9a7e2 SHA512 c9a81c78d87162f71281a32a076b279f4f7f2e17253fe14c89c6db5f9b3554a6563ff700c385549a8b51ef8832f99f7bb4ac07f22754c7c475dd91feeb0cf87f diff --git a/sdk_container/src/third_party/portage-stable/dev-python/pycparser/metadata.xml b/sdk_container/src/third_party/portage-stable/dev-python/pycparser/metadata.xml new file mode 100644 index 00000000000..01a95276e3d --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/pycparser/metadata.xml @@ -0,0 +1,13 @@ + + + + + python@gentoo.org + Python + + + + pycparser + eliben/pycparser + + diff --git a/sdk_container/src/third_party/portage-stable/dev-python/pycparser/pycparser-2.22.ebuild b/sdk_container/src/third_party/portage-stable/dev-python/pycparser/pycparser-2.22.ebuild new file mode 100644 index 00000000000..757db29f1b0 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-python/pycparser/pycparser-2.22.ebuild @@ -0,0 +1,69 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# please keep this ebuild at EAPI 8 -- sys-apps/portage dep +EAPI=8 + +DISTUTILS_USE_PEP517=setuptools +PYTHON_COMPAT=( python3_{10..13} pypy3 ) + +inherit distutils-r1 pypi + +DESCRIPTION="C parser and AST generator written in Python" +HOMEPAGE=" + https://github.com/eliben/pycparser/ + https://pypi.org/project/pycparser/ +" + +LICENSE="BSD" +SLOT="0" +KEYWORDS="~alpha amd64 arm arm64 hppa ~loong ~m68k ~mips ppc ppc64 ~riscv ~s390 sparc x86 ~amd64-linux ~x86-linux ~arm64-macos ~ppc-macos ~x64-macos ~x64-solaris" + +RDEPEND=" + dev-python/ply:=[${PYTHON_USEDEP}] +" +BDEPEND=" + ${RDEPEND} +" + +distutils_enable_tests unittest + +python_prepare_all() { + # remove the original files to guarantee their regen + rm pycparser/{c_ast,lextab,yacctab}.py || die + + # kill sys.path manipulations to force the tests to use built files + sed -i -e '/sys\.path/d' tests/*.py || die + + # Ensure we can find tests in our directory + sed -i -e 's/from tests.test_util/from test_util/g' tests/test_*.py || die + + # unbundle ply + rm -r pycparser/ply || die + sed -i -e 's:\(from \)[.]\(ply\b\):\1\2:' pycparser/*.py || die + sed -i -e "s:'pycparser.ply'::" setup.py || die + + ln -s "${S}"/examples tests/examples || die + + rm tests/test_examples.py || die + + distutils-r1_python_prepare_all +} + +python_test() { + # Skip tests if cpp is not in PATH + type -P cpp >/dev/null || return 0 + # change workdir to avoid '.' import + cd tests || die + + # Ensure that 'cpp' is called with the right arguments + # Tests don't seem to always pass the include they intend to use. + mkdir -p "${T}"/bin || die + cat > "${T}"/bin/cpp <<-EOF || die + #!${BROOT}/bin/bash + exec ${BROOT}/usr/bin/cpp -I${S}/utils/fake_libc_include/ \$@ + EOF + chmod +x "${T}"/bin/cpp || die + + PATH="${T}/bin:${PATH}" eunittest +} diff --git a/sdk_container/src/third_party/portage-stable/dev-util/maturin/Manifest b/sdk_container/src/third_party/portage-stable/dev-util/maturin/Manifest new file mode 100644 index 00000000000..92b012d0e63 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-util/maturin/Manifest @@ -0,0 +1,703 @@ +DIST adler-1.0.2.crate 12778 BLAKE2B a1dc17786adae945ac09d3525e609ed944e6465690787bbb831a1b9d53793cba1989793d0a5606d5d23ee20d36457923d451b1b3530c9ec7072a487aa3e55bbd SHA512 7ab190d31890fc05b0b55d8e2c6527a505e06793d5496be0b3831e0513412f9ba97f8148f6f68ed0770fa9cd980a5092d885e058becf1d5506b7c74b82674aa1 +DIST adler2-2.0.0.crate 13529 BLAKE2B ec575b0bf12e321399ac3a1d59fce4ddbeabcc60cb3d7c2f362cce23eb29b4ea836451372d6d88552a4435ae29bb41d6230d55f625a4359eace680b9b771d0ad SHA512 12d12579ad617cf1a94cf95ab9d3f5db566c3b2de4bd5735eccd83c668fdad0eff134c996b73c46cbb9f932837682043878b8cc4764191625e9f93ccffcce423 +DIST ahash-0.8.11.crate 43607 BLAKE2B 7dff8e41798ba25df8c4827ff414a182bb25da4825f0119a74916fe775db5445b87be8fc87f7c7f98d3b5053e1d47546f98873de1a942d36e5f308a3fb7dd620 SHA512 47d211b2422de0b381dfe32229faa346406eb7a22dff867dc04c22389609a8671ce3218e662000c49891a06c259d82e0ff4413740f007729d80e097a6c3f0d9d +DIST ahash-0.8.7.crate 42894 BLAKE2B 56f4b2f577eb2752e675fa2b3191c65e0bb88575f92e8d906714296fca1daace46e93256672fce08cc5b4ac11d40a690a06b32a99fb50fd0df4f042773c33b6c SHA512 2c9eaa22f7bda47a781994c769d4a2ef15ba0f511fdd4ec4680c13d4c1809f1ce01adecc3b3776793158062d28ad9e5f0b1d1c0a9429e43dd07cd99540eae7a6 +DIST aho-corasick-1.1.2.crate 183136 BLAKE2B 2d4306d8968061b9f7e50190be6a92b3f668169ba1b9f9691de08a57c96185f7a4288d20c64cb8488a260eb18d3ed4b0e8358b0cca47aa44759b2e448049cbaa SHA512 61ef5092673ab5a60bec4e92df28a91fe6171ba59d5829ffe41fc55aff3bfb755533a4ad53dc7bf827a0b789fcce593b17e69d1fcfb3694f06ed3b1bd535d40c +DIST aho-corasick-1.1.3.crate 183311 BLAKE2B 8dfcbba0b9d94e55eae739b16f5c6474baa43ee7854c5ca792f426a9f46fb0eece79cd493b804e51449181bcad338b96819fe977c02c9907654d713e26b9f830 SHA512 ba422a54688c4678fcf16e34fdf3ed06c333e6e3fc8b75af9272a215add494d43ebaef319021134b61327fd5d3572aec0dc655b714ffb3bc71ba3c265c9ebb69 +DIST allocator-api2-0.2.16.crate 59025 BLAKE2B fda69b52435a7243eb19bc55914a1961e59dbad5ac12c40db39cccdf7a99c742da59c3ef160350808698db24b91e0ce655cd1acedbbcbe20c717604aae23ea5e SHA512 e1eb0df6b44b62115795ebf772f81e9ac0b6d273afd81659dbddb7eb6628b6e5ef6a60ea21413e79ee638afb72e6872ba83a075f6324daf93f2f1eda48daff2f +DIST allocator-api2-0.2.18.crate 62504 BLAKE2B 8152c5a611be91ba23b1e8647511e21f48e7d4f1a7b9a828083f5bb8747cdc92aee66f73251b19195bbdc1f65aad992632e820d86cbeff287d598257ae3628a6 SHA512 5e5b0e23e1f5b259e5d3746e3e05817af8dee95af7105ea775a5c1d69b4e537a4d6a25e2c1d46ab83e2385217b158f7940dc1315ae581c35ee23289647105e73 +DIST anstream-0.3.2.crate 19504 BLAKE2B 617b846c244ea4ccd6c7835a382afe85e14c245ea56b678f57ee12e9c7bcc1c0c3db9620eb4d16bf35e17eca38968bf04420b758f482ac5594670e6292c1fbb9 SHA512 b896e5208a2ee6a3c98bf3bb9ac1c52792de114dfa5709dadcac6183ea19ea63230dffd3217e571354a71d69b8eafbb0189e05f8f77f50922020de54e3aeecc8 +DIST anstream-0.6.11.crate 30239 BLAKE2B 4ac585ec56a804239d32ad3e64d93936ef9d5c8e0f0e2df17f7b081b6a3b2c4c32ff4ebc09ec02507bbed22b025628029d859610aed90c024e19a3216de73c8b SHA512 f8dd65cc116a1495782a3bfc98edfdd0973ab22ea2fafd292fb4bd3495af7b5ea410f320d3fa05f7f812fa96c2a20f4cd2af9fc58869a1a306f32714cbe45163 +DIST anstream-0.6.14.crate 29160 BLAKE2B 1120895a51ed7a285c5d5a03d2f7e26dc956d95f39cf500ba9f547d71a62ed0326f519860ddcf8db77cb09e9119e914a62693369eca51cbf9c01ef874ade9112 SHA512 65ece20958e3fb1ed4a5ff1d45f5bfdcb942c64994a3d14eefb0dfd5b04f433f6e1b06ebff240c67ed8ff7cc01d93ca0acf8c8ea29cb41309c6c882e7c192b34 +DIST anstream-0.6.15.crate 29231 BLAKE2B cc4cf0f381c210fecc20b5796fe872b533419e5f957021b0c3be3cdc23fb84ce029fbef6f9b6f174a76ad713c07f0811145a70572de7c24cfab060fdd990f49a SHA512 1cb01a0293b4c9bcc010909707e71c464416d3ec6fc9789060b7aa9fe4cc04424fefa8013cc8765ccdae6dfd9a1c50a11f7b30b39a32c4aeaf525f28167ddb92 +DIST anstyle-1.0.1.crate 13977 BLAKE2B 35be03a7de78737592528967e8ad4851436a74c7863cae9cf5cf7366d3cce9bbbd255b1a89401051f82fe8569a0ff029dcfe427c14a2e0677890453c6119d241 SHA512 2bf9b83ad9772c6a3ef28239cbb98bd667dc631fd1ef76ec5029825c128f6cb22756bb1548dd991e482f86eb9fd94fae5c648f91de2c0d71754b6dca4ec2362c +DIST anstyle-1.0.4.crate 13998 BLAKE2B fb501700855709e53438461c2f4b48d869613e7bb3bb700db8bd0d95082876d3782dc2cfe3ce110bb4a206994de56afe0e90fe89f9ccd07c60fe1c652123ba59 SHA512 671c6f57106198bcfc2f9000aacba98fabacfadfce2329dfe8d0e0a2af9404da483d7a844ca2b08e1fc0249371f574c13d0082c9f7a4ed90ff581308257a52d3 +DIST anstyle-1.0.7.crate 15709 BLAKE2B 872e0ed09e7e94c6f6b812349e39f949aff4d7cbb87744ab26fe49f57a7d330e0f79447213374f7f862ea276aab2dd1077dc8df3f7c5f34079ef30c4d17eeeba SHA512 e20d49f7d148e03f7b127be7802e0b6b7a2b05720614d46c2ade5e440ce322b44ddd3a9239b897886faa03ed1cb30f947ee27d3811fa83dffba10b3975eba7ed +DIST anstyle-1.0.8.crate 15771 BLAKE2B c039613e7de27cc990e5764810f9351754b160928a8954dc19041354cf9fef1422ed964237a5d39d16e4e9f8592ed52c523ccf36b0b5506f464d4f818f3332ff SHA512 3b867f73df0b2f69a0c7d5d6e62c7515045e053656afaa303e5aade8012e838cdf5d15d2c3d7c297db9e297d08ea69a9c8eed04b97922a83f56c58962c1c0b69 +DIST anstyle-parse-0.2.1.crate 24802 BLAKE2B 6304a56c6a9fbaf1bb4d1d177b2315684345dc9d71c35836f9544145364f8d6eb56e25c03076690c594ab7db5914501acb569f6c136952e59c93179ced527fb2 SHA512 5c8fc7d88ffc3a6e78340ffe0f3c2d72e865512030ade4509de9c673eba955c536bb1873dac11f6ba11cc8367fb30c67451ed65d19f81507c9e917c702bfd176 +DIST anstyle-parse-0.2.3.crate 24699 BLAKE2B 17e8638187ccc1ca0174a8cec7f7daeee7e0d8b8c430f7e74f9b10d8de4b49fd1c6facfdafde305b7a3e55b1ebf2b4e8ec4975a0cce691514ddae9eb5b5e711e SHA512 4a6d0f706d75c9b3c5144f34efdef3ef8fcd075962c594a23a6209ed56112563a34b3c01e05a08a0868d59204272d06211b2585cb9d06ce075ea875bedb2f399 +DIST anstyle-parse-0.2.4.crate 23069 BLAKE2B e80bd81e351326a222238b3f559020a2430ac37293e61b6b6309b37bbb8bdb78ec11ca9c0fd270098af5e5ffb2f5660cfbfda949d20fd2efd336ed1c143215b2 SHA512 c1dac475df77d090a4d2041ba40ff418abe66e93e4ddda54653bf024fb4995e431166684343509a2337bc813fe06f362d3df8a1d7d05d177cec1a488bcb9942a +DIST anstyle-parse-0.2.5.crate 22680 BLAKE2B 7473651b1eee08857a6ed1419d3d62ba4b9a9aa0d6657965ad9c67bddd793d825737d3804961716a89bdebed9879ac43b42c897cd229c6e7bd780859e1e3c247 SHA512 cd94ad0e88ad4547a660da1473bf4e6dfed805a066782124204143c7f754c12db719bd3a1774c299f1a035740bfc4830919da191bd14e0acede410f6dbd1e2ef +DIST anstyle-query-1.0.0.crate 8620 BLAKE2B 2d296b5066fd6284a2410923215571e6df650c5ef892d6de7a7088a0996ca30608797feabc84f3c325ff4d07001dac80ac5067d2a9c9d15d9ba59a276b399f53 SHA512 2781be5c82293b7ae338ec5046fbeb130de9eb2dbf2e4dfaa73ca5233032e1e52c133e141b02f33d4bc36d996a0a3f680ac82d42d614a5305005f60547133c7a +DIST anstyle-query-1.0.2.crate 8739 BLAKE2B c06643e8616f1f4469a32f9c0512941ce53ac5db9ebfa7a5b2f19233040cd4438dd2ee69ab89ecbc1c239e92b674dea9df15ed673408c6f3fe21787cc17d76f3 SHA512 f409b624cbeecf58fd87c47f85be28cae1fe48f65d692195fb80854c514e38c40d0e0ffad3a5b388a3929c47bd2060302ebb635aa98dc57329f3a5ed7be3e2dc +DIST anstyle-query-1.1.0.crate 9832 BLAKE2B de106e289c874bca806214e275647415bdd02e2878f3a80e7d337cfbcdb755d8c182b2879371f00f5cad97cdf68224ac11ca41cc89ad7ab3929f854a9f9e76a6 SHA512 321ddfa7b090142116c96bc8c70d81cec3e816922249ae0f07389e2d1b62c8b40636675ccfdfd23d52e29c162ae7d929637dfc7d697dafb79e596d04eb8cd90b +DIST anstyle-query-1.1.1.crate 9891 BLAKE2B c298114c1864a5233fb39c365e079a7f1f4ef23499dc330e5deb06f83f27bc727015befef79075c7e39952547f799b4135d7db287cf72dfc914191df784a4989 SHA512 1b2e888f025142a0d9b01314cf083831a2a45d8da737c1be3a6a9aa177e73e0d2ae7999fe7610dd450b7096115e8cf38c5da23723cebf1deaa7d3501d3dbd5ce +DIST anstyle-wincon-1.0.2.crate 11712 BLAKE2B 68215a76e44cbe0e69c4111eaf7cd818d0e743883aec01f99f6d96e863d8d36bea67ed112db715a3a0daa348535f3db50547d8a0ab5e4572975d68937c49aa86 SHA512 8bda8b79785d201cda90c8d3544f5cead955c25749a4b828bc897e4bb132acbbcc50ac90ee07323ae3077af3e4c613264871366d70e5211200d119f4ddb63b0b +DIST anstyle-wincon-3.0.2.crate 11272 BLAKE2B 73e124773f618a744b17017d4680ec6ccc84ff94fbe2e565073fbcc0facecd3cb65356cf27746d07f453bc917cbeb2ade3a618c6b8578d64cff4828c99569868 SHA512 4cc194faacffa01c6989354c1cadbf1134f0945250f67b7020ab5b475e30db34c799176bd335a6265386cb9c5e8b5bcbdf35894ec0c809b140ffe1c406751931 +DIST anstyle-wincon-3.0.3.crate 12179 BLAKE2B 37793975a05ad60bb2b670c208db11c5cda8a2a456242cd118748709d0a220b541b6f088676eccd19870cfb8f910d4aa1e7764393785a6db0531af4a3ffc8047 SHA512 55217c65fc9ec674e5b4dd70716a221bd108b507dce9baaeb542f0e0a47027ec7fe61f9cd3cccfda43e4a4cd785b42f13400daf89884c32d3768e48bdff2d179 +DIST anstyle-wincon-3.0.4.crate 12234 BLAKE2B 23294d6ed7715c55c8f796eb7b860450c57b22b57e32a5c75847f2e2bd68a52b33c24797db662aa5fd7e799b9644075c8c939d93b0cf8598b16ee80fc817b77f SHA512 24b3a9a44382609ad449425a657d4b42a792d4703c36e0953f09a03817759c266a2f0ff4ecc9e8b93ea8403df2badef1f1af6a6e50af56205176c41b13501ae6 +DIST anyhow-1.0.72.crate 43837 BLAKE2B 1547c158882e50579a568a14e6e5cd162feb6cf291835266c9dae0c1c4df05a7872bceb02bbc8a13ab5bb84d299a94892057f54eeade7fa095ff8f897f6fe9d8 SHA512 25d8d4cfcc9679c9125fe03c7ce5a46462ca66e7457d45cd7838b7867f3461a899f75b22d76dfb04caa09c013c3b702313ffb6373f92b2798119a30199c38a98 +DIST anyhow-1.0.80.crate 45138 BLAKE2B 4985d3d8f1d5b5886fae5c7d1a61f921d3d64fb51e24710044b85dfadd2dae2b25b8995cab419cb7cdb5c8cb6b50ad0de93b9a942d34bc45014bd5fb9aecbd39 SHA512 481a3bc29de2af0b913d83cc79dacd559cf0bafecafcc707b921b91a732df953a2df582a54e5fca3f506f6441fd47379bd6bd006bcb1bd6f2615198f9903cc59 +DIST anyhow-1.0.86.crate 46741 BLAKE2B 21b1f3acd1c1b659e6e9a53693178de67c806d7dbad30dedea0fb7078b2388baa196d1e7240a7dc88ed9dc93ee4c00bca8e608dad1b6bfb5bfa4f4c5ab51f0d3 SHA512 3853da32a2c53d73969bb29a1e622f3a6d5832d8888dc6bc8eedb76394b392f983aa3fcb1f542933e238841486106f0f38e9a2400c12c7699baba0ebe1d8193a +DIST anyhow-1.0.89.crate 47078 BLAKE2B fc824e72891bff0cc7aa3b538adfb9af7dc843ab6ed12b8b04eb70e62d32aae1decb9090621d3245dbe89841e73080d2d86973b4aee50873e798956da9b3faa6 SHA512 3c09317089ed78601a56c626700d12c0b49396e25fed9a9f05a2dbfbd6f91ad426c430633006a4043decd1f70a85c161c4f8dd7de0e4c00b82a169b89dda8da0 +DIST arbitrary-1.3.2.crate 32037 BLAKE2B f8f6a10a8f42f14eefaad4348b6ff200d0c2fb22faa7a2876247228046359e39c555f3170a1975f64f8537319b97c7ce2030dcab3614229c8334b5d6f9248114 SHA512 faab26c44f25d2c7298add2a657e4010d9fe24b3a61e2270bc6feac05cf2a82895fe225d2fb1c6b63e6c7da54e061955503f39322b96dbdbc4916601bd5e5ccf +DIST askama-0.12.0.crate 16773 BLAKE2B f0e9d355de0092334b65e669d49b465f02fcffc980d364ba8f478951584b43b890731e7d994358fcea1e5aebf62ed6649b1b2715e9431eefa4820ac0d57f0638 SHA512 8703a9091bd0145c12b724b116452be45ea8730fb05eba375af321345105105fb1486511e3cec82c494fae8771b12632caf5a01e3722a730cda6f81033c470e5 +DIST askama-0.12.1.crate 16976 BLAKE2B 9257c6d292d6399d81a750ff4b55958a0ffbdbd5f96f3e0f2ac1e777a8bc8e11264a89bdd6edea6a6a3d0b3324138c1524b0f00fc2168afd1abd0f4b777e1473 SHA512 b719134fe73080e8360f35ff4ddeb3039ed1c4d20861cd3cae40e20832fcf8b12eb8b04ad82ea49d5c5f5ae6fbb29180aeae7e41be5f72ab97e9abfd60cceb4b +DIST askama_derive-0.12.1.crate 38245 BLAKE2B d16ac4cab01895349a20906a90ee72a366a320db79be57de0959592f65276beacaa726563d93b5c1e08a603652b20163aa513dff47b2d91b2040af8e40f5bb07 SHA512 6b627746bbc00cec610903d1ca09e723265b68f3c05464800afc69f152f5bc44a4c83e76932d0dce77668d0ac1ce4956d57ea4bedc3efcd0b473eb8fafe1aebf +DIST askama_derive-0.12.5.crate 31218 BLAKE2B 0646c0df57dd6d3d3f48424db2456df37c11cbf1bb159570f7bb3e878b0abce3ebf9e948554f214dd9f77449ed79ade4ffe88511e66274d3d4beea8a8e1b539a SHA512 37fd963d0aab2f29866931858f3235086170133f86953f70b44003e9505a5c716ffa6ed7429601520716259688cf2e4cb17649e89065d210eff28119416773f9 +DIST askama_escape-0.10.3.crate 8875 BLAKE2B 6bb88f18aa0bd05a36e7bf5cfcaed3138ddb96ed366e7da9b9a64c4e0345fba384cfa3e9bfab3674c1697a7722bd59a9428438b78d44bcac78740d4c53c3d3e8 SHA512 1978add567021fac7f086b6091c97de81919877726455828164642c55607d5b5f6f01c0187f8a8a3371c9b3a1ef41f4c3c9e14d9068826c38ee8a6efe2eeb5a2 +DIST askama_parser-0.2.1.crate 20707 BLAKE2B 14d385d906295c892543bf917a835b9b354666927a63cb66c6082b8bd7330b07b89a1cb60a88ce0b8a8a58cc23023587fdea2117329bf384a22c097c0e45aaa6 SHA512 50c2a8a1f08006b375c450275ca7b455209aabcaf2b5a2ed903d1f8cf26920d95985e1ce2b6d77397b8dc32cdcbea6c442a1b4f590af64f92e4e5b47e3a52f75 +DIST autocfg-1.1.0.crate 13272 BLAKE2B 7724055c337d562103f191f4e36cab469e578f0c51cc24d33624dea155d108a07578703766341fd6a4cc1ef52acda406e7dba1650d59115f18261281e5b40203 SHA512 df972c09abbdc0b6cb6bb55b1e29c7fed706ece38a62613d9e275bac46a19574a7f96f0152cccb0239efea04ee90083a146b58b15307696c4c81878cd12de28f +DIST autocfg-1.3.0.crate 16524 BLAKE2B 7d5a03853d6b4f0da08d8e139fb200da21e47fa7e50d1956270d0ff0cc496f660f8f800122c95eee9ba98d9210ab200c3010b782097483d12d6be4ac0df0e7c9 SHA512 a5570b955d57a7183ba148b335837dc5af24b202e80681027536d33fe2822509ba644fc70c29f018c893285ced2bf6774f44ca6c59f7c7e2226d5349cf7c3635 +DIST automod-1.0.14.crate 8717 BLAKE2B aaf79cd054645d3fce5e57f96bdc33f0d02c66495353f4155eba37e81160cd3eb3019587770a38bc22cff5f1e673f0af1b0c9e5e6472bd08e9a6c2812c71b576 SHA512 5efdf134f24298f3a522688b3bb87f5e8e43bafd761909a09a1018f7142ef0ce3ed390f7f01cc475391bf8e6e3d433d776c47efce619a403276ed8998b2c531f +DIST base64-0.13.1.crate 61002 BLAKE2B 3b3a5b26e2ef18e9b4f1ede72b1bd160a1494751878e8441d463f8a514e6cb9ac859231536989e19fb1261fd864617fe31440df1b5855a0ec625521fc6fcef91 SHA512 1eb76aff9a84057f2ccb7082e9c57b015c2d71a28173089b02e7aacd09a7d311bedf0a943529611ada29f8d7b536d7ae4de256d98eee8450003a3a9a652bda4b +DIST base64-0.21.7.crate 82576 BLAKE2B 25cc8761c14220981ff4ed332058f6179948080cbfa2b225ec1d1602e4af14cd470c969e8b7049117e6fc51a5a24e06b1d27bab844486ecb76409d12e0581d5d SHA512 c6986d88dd9aa081d914f35b4174be4ba874848657ac4b5e63b9b45af765d973289c548ccb5a01584edfc0d8d79ff5be25b51365295d6e7a311bd7f0ae3c0cb9 +DIST base64-0.22.1.crate 81597 BLAKE2B 6f216a560bd36e6e6b74e908344b457594cc768d9763070e269b56a14b150cbfc4b7f599d4c2a0a5f783638170ee132f0796fefb14fcac7fd73c58db0791007a SHA512 91cf2e4e7fc8815f9b8a86a7fa722a20eee3dc1dd57111b29e420de87ce7836bcdb1db01d3cafb9a977710ef63e7cc41b7772762323e68e0e832156858aace20 +DIST basic-toml-0.1.4.crate 50206 BLAKE2B c9d3489862c6e3140c8aacf9bce95167ab8f52a514019db9b3a8d92052403b4d6d7293881345addc23ad0ded715f6e2fa9b691f6ca241e3e3b0b850bba43a19b SHA512 03f0aa90b948edd943d924a33b83370703139de0c4d08e8eb4af8429f0a5b7df35c5b7027b7d5bca0ca332151fc5b7567e29ac8357efea8cd855e0e6fb094fee +DIST basic-toml-0.1.9.crate 50234 BLAKE2B 152f592ee16fe1542e93aac6263dfef01357572d424127978e6d74c8f963dd40292a9dec9d25ea7cb17e375b536590c21f6e4b100e71a957f20d7c0c8f6cb3c8 SHA512 b4221510ebbfcb1e839556c5ab7d1b98303e9f3866bae5d0f2d4ada25aec7d07b659eff1c43ed91621033642bbe8c5bd139975e086d1b2e9998d59f58a688097 +DIST bincode-1.3.3.crate 28958 BLAKE2B ea01d2efd8149ecba5e240ed989268b683d542a5f369902d316a4fd1ae4b8edd94e2d4a8cbff0e96646eb29facb04a84b249d74f0781dc3d29c8797ac975aa9f SHA512 49e39d71214dbb623a18e3852f6f2f2a5c3f951b64107d66c8adaa95a442a3283fba978bca41b126c9879b12833b945f478d2c77d35482b3577fc1a894e8e5f3 +DIST bitflags-1.3.2.crate 23021 BLAKE2B eb990bb27b2bdeb66fd7212ce582cb36e1c616debbac85df642d0c82b25439e6bf9b1e811fac76b59e58ea3c1bbea6170d03a61e8f9a395e4334a0e2e2987eda SHA512 3c698f757b5cc62f815f9a1cce365c3d2dd88e4db71f331dff8bba86c2865f755b81cb4c9bfc59bd86b7643b0943f9e09a7c4f8ad75eb2ab0e714803d0129f62 +DIST bitflags-2.4.0.crate 36954 BLAKE2B 1d6cfeb0a17dc53a6249a83c8c7ad7c102985ffcfd7f7f76506889684235e78fe489d23b5a5f9018f0bd526a38d6b1449784c62322fb01f4bb507c0af8bd545c SHA512 0c3d6667abea48811a792749702136ee3db97518b33bc4c7d35737505bf56315e0e5810deeea28b7a1b540ec0e21bd319ba0b3c5c4aef0ba8ed5499ffdfd9b0c +DIST bitflags-2.4.2.crate 42602 BLAKE2B 768d4ca52aca73d8acf2f494a66957ed2603eefd5a04332ed0880d230c2cc6ef3bfdc0792fa6f288a0eb132913dbb256793e580bc34f4a40e8200e1fbafe97a9 SHA512 ef4c20e6e78a2ecee97e17189b7100a504d8176c7c15d7f17d62157a116d66f83f8b2bba472a4acf02cd3edbd94b20a7047af918c3f3b371e2e04f7474be0214 +DIST bitflags-2.5.0.crate 43821 BLAKE2B 2d2a78b0a19dcb39580e6f73ed6c468b0626043010b34661084944c83561fe49db24bee1ab57fd692d57617be6506d529e095aea27b753a77e26d0b1ebf7ed78 SHA512 75d7a89e53e5e7582591932bc430e6a1db7ed0f914ded6dbcf957125be52975598df7fee14ef816f66544432ef0505f0a081f3794d17138ec429e283fe14fcf9 +DIST block-buffer-0.10.4.crate 10538 BLAKE2B d819c4f9c4be85868e8b105fb7e479d2e58d3ed85c3339bd677a3e111f85cb1ff624a54d7802ab79a6e1d9221115f66388568340480fe83eae1cb448f19f5b11 SHA512 b7d436d8e627e16e6ddc300ee8f706a6cef28ff6f09eff848eedee46f84bdcd03601303c92ab8996042e55922866a59259948177c0a4496eed723523e77f6fdb +DIST bstr-1.10.0.crate 380426 BLAKE2B 19330a5a293430c09908d2174ff814351b16419f60de6463abf9b8a9dff06a4e6845e889d8047a710cef54842f2790d9cd5080b92cdcb113d89742b869979c74 SHA512 823abdbda9b13802facc7d6b1ed9ad809ed3b0b827d26e418348ffb8481b5f5735f129c5a9a8c7b2ab010d7f32ca57cba69a1ee10a64225c54c6ceacd22c05d2 +DIST bstr-1.9.0.crate 380170 BLAKE2B 06ae5065a5d566b6333e911a5b97e3999ad2f0bc19b27023187004c81cd01e5315dcac920ff87a6bb87ccfbb949364f1361dc04d342e24f9f54490b5d44a81d1 SHA512 dc313a16c38ad881128977a20bb390e7c95a96d9530596433a7c4fd7f77d5fffd079d436006dd8d2bfc4aacdd7f0aff229504444250418f6aa3f8d6d4df9abba +DIST bstr-1.9.1.crate 380305 BLAKE2B 52b45bd48874d052636c6b451cc36d8b012808ea5193e0188e5edd09f81d21b8306926cfebb405ad0650ec9aa710f609bacaa773bf854b21f4803dc38bb2eca7 SHA512 67e9f76719310de60f46adf3c39768b4dc078d4c32dc6bdcec1a94cd9f630c5238e427ed84cd6ec25a44f54e84adeb795a0e92060a5372d9fb9ad9f0914e3172 +DIST byteorder-1.5.0.crate 23288 BLAKE2B 7f85a7948406844070a2c8202e0bd52f73b3dfc7c666a97046128044eb9352195afb80e2bf894c0742ad109e4473339de1365d09591de70dfec6c8c02a8e1453 SHA512 96caf981177f6ded9f27f025922cb94eb0cd9de5303bd91680099912d922092e77b7361efa70011e84f1595e443193e4f1b354443b9980c123f6ae573b236f7f +DIST bytes-1.4.0.crate 58080 BLAKE2B 99a9d343424e04649bd209bf2a6c3a089a6cc9fdb799968f8c3a711189328e4499df2e09cc6a2a8ce05d2cc668149b364cf30cb3b09e96e21d50a39519c2f49f SHA512 502c63b9fdcd36ed28ede55a63cd359dc7b28658ecd43020511d17d48d7c34e45aa8ff7e4b17770f12197451040c2b724fe68d2aa3ab4f81c9171d052f2aa000 +DIST bytes-1.5.0.crate 58909 BLAKE2B 2931f19e813eff73be407677622fa29e45f9b49434d5b3a04104b56563fc0e941fd8c5f996258a1aa660000ef014668d70b683b751af8e48d28d0aea76890c92 SHA512 6654cf41d8f0d7e19b05fd95044b9a3bfccd81f469c797c6aa763a4dd29e1b34064bed2e094548d147045cca7bc4706059de5bcf9f6579189e6068fbbf1c29a3 +DIST bytes-1.6.0.crate 60605 BLAKE2B 3e4cd094443969c6062b51917ad9df314b61ec9ddcb0336cf2621d8966c568d5b1fdbf16b11b5e2fab01b43ea76f6609f753eb5c2380a5e4aa8fb6e807a2ff5d SHA512 6507bc4274204d0a19b6a95c3284c52245c71cbf5f2dfb5cd372193d989e49869ec557c0c4e449e96ed4e3028c90606dfb0dcdc1d72bb234a36bc5f344c0a7a8 +DIST bytes-1.7.1.crate 63623 BLAKE2B c399f7f25b85ac284bd2f139d895838eeba7deb56d109c8579966be4b8a7a56bbc26f9387bd0bef9fe5449d5e2ae8d11b254a7ef93048a4827d945ddddb5ce09 SHA512 04cb5bb1718ee378be1d9d56aef2d117ed561935ddadd78139ef2839f998e92c88369c79560bce9d23246a3ebda1dc888af373f9ad4827a0b9a249379bc71e81 +DIST bytesize-1.3.0.crate 10164 BLAKE2B 049f292705082dbd3b2f0abb6f153023613107949f4849154aadce2181f4568ea1b3c12f00b6ad56146f8a4f3b07b7025498e0c989ac6561ac7255720b85ffab SHA512 c718af51b0da2979b70142012544fde6bbf8639cd4fde66a8066b138f7f58dce019209e27566027dc0ec5a7fc1d2ee17b9b6366cc7a5f95a6419e29a0ffedab5 +DIST bzip2-0.4.4.crate 34197 BLAKE2B b69f8ad38b44eb4912b33d53467492b0ebe6ed740451bdfe9133e71c47a8dbd85b1110a9607c4cc627fbabc44cd86fe0396bb545864632ffb6169f9cfa547b6c SHA512 9cd2b9159bd0b42ac908ecad41f0a737272af94ae0d6dcfe182d2f44bcea4632d32b0456f02322047ea9d6f46377db6cd083f468782bccd6126bcc75cb852555 +DIST bzip2-sys-0.1.11+1.0.8.crate 633444 BLAKE2B 01578c512443134fc786669bea4f2ec4b9c457b9936c907315299d8b67ed78045d458c83ccc119f0fad511529fb5af5feff5fa2d983fdae832d2fcc1b343e102 SHA512 d0a86b9f03acb1e4e309d5739dc2e88cab582757d467a433afe0017017f0e5d2c0282529e3a117160958ed170d8d695ecae739805888305df0e35e4dc440582b +DIST cab-0.4.1.crate 25985 BLAKE2B 5b30e5e810645641dad0690449f597551b99715cd054c04eaec5d702fe7de8f9719a217bc1edf335075df77c108af1e562c117d9276d9ab10350f5e2fbc42e2e SHA512 030c897f544c8beb22dbcb43afa1899e092b28862dbf08ac55ed2b1c7ad02b7b646b3b36424243a38d83299a7bdd05886158fe7c8e7b17e756921eda98b8ed21 +DIST cab-0.5.0.crate 28101 BLAKE2B 00afdca33aa5528ac121055e31f0530eaae56db7907b93e3d039eda44dd193ffe4d19aaab2f14bf838d868ac6c13bd77925305ac4d1f57c7e171cc21d4d0c91a SHA512 9f764809a746b3ecb17bfcea8295599bb06f167253d195f9bd9c9756c9f5ddbc82313c8eee73472e386c6c6b25128011a0687240bfe97405f957464cda2e1d13 +DIST camino-1.1.6.crate 30519 BLAKE2B 3696bee362c9a6c7331079f86823aede0df06c1c36fdc2d11c0628267ca7635fd78430cc927cf3b2af34591537d3968b3c5f1cf9d500f3e889c202c944fc6138 SHA512 e777cc6e2a01c95931a81521eb278156d1c50ffd0126f914b21e35dbb7644b835f3c26bbe7a487bbca508d26b4c933bbbb9e051fa42825b154c2fa03c04375b0 +DIST camino-1.1.7.crate 36204 BLAKE2B ea87922e77401a23f25d66af303f39c568f37377e4f0cd6d206cb7b175a51528680bf67897e3b9830d276acb1b156b7c66e149b75370be202cb99fbbcea54233 SHA512 b82c809bd52549d16e286d514b5dbb1d640633b7ff05412ce3539e543de9c69d99bc3f62597b94fc0cedd7c8034ebf73663a6f647e46409b778baa4877928c45 +DIST camino-1.1.9.crate 37552 BLAKE2B 28b21517730db408598f83e269ee8aa4dc5388c4b491779ebb6e76c478d407f929bda6906d88d429828d7f01be1762c72ecbb6d8c7aa4a1d1906109a17b45df1 SHA512 27a6a3cf72c46f15a6017aea44a048f2a8eb577aa9d2a088141b1cb7479106152ef0bc00a6cea9332c4df4d0c54aa6bd3dc21159f15640e347407c15a1bbf7ea +DIST cargo-config2-0.1.24.crate 63106 BLAKE2B 2a0eda6f4dc2272aa04142b9018379560e755562672c4d6fe22e483f87151aef3e34243ad084facbd6c83e7f14b02413bf0a608e3439eb8742d272ef9b966535 SHA512 ba894b809579e214f3cb4a63f963a88e774f89d83c29af13e0868b09fbca081a9a6ebb0e6d4693e816310e2703ea0e95a453450ed38dab22ed6c19a75e7915ae +DIST cargo-config2-0.1.26.crate 63535 BLAKE2B 9cfe8842ecb8085240adb5a428ffc3a7260d4227c11edab3bc280dd8a9ba7f08f5ad3600224fe7d1b7d6fa4b2a19125656c06546bc5a3398b4e5722ae96bd9ad SHA512 4e30355eb26e796098803df43f199f2ebfbe510f467e32cf39b3784c9b03156551d183eb46c5f05cceb41f9761979aac11746be6b2473a53e49cd066794771d1 +DIST cargo-options-0.7.4.crate 18149 BLAKE2B 0ab8537b5c6d05f80e78209f9656dbc8cbaef0d2ad14de561886d573ce7ac6d1357d082177d6ea83809ffe5b85795ae8f1ce1529d063ef916b30598c16b71499 SHA512 241799e4d60bdcbbdf45fd203851165b84fc571179bc209b877153b83f83d9913203276ffbd5de378abacacfa4d1b41f84e3cec9cd78520e24b36c5e5e673580 +DIST cargo-platform-0.1.3.crate 11230 BLAKE2B a67d0f77015b85c7cc8e9cadd5eca3c1ac57fc5c54345f80c9892c4ca7a4bc295f8e23330fc9a51b4954ab4fff7cf2a6ed509b506bf801baad6882f19f173404 SHA512 09897871995f40ae792cfbc58a46b602ea9e28458cc066bbf89451edca6755809816ea7b927cc7f35aa95a8da35e1765d38471bd9317946f8c3c81cea82d6d10 +DIST cargo-platform-0.1.6.crate 11668 BLAKE2B 6cfb4a3c6f1005481b80cd41882c5e5d42912d9abc2f9aeb90464d2c5e904359ff1981852126b49bf7877bd72ad6d295cf35a0b3131d3b84df5c088f346812d2 SHA512 c1e6d8ca372ecf8b23d0580bf45bebac22c0f7460c973e65911bea023deb9f47e65e3969b4940f308a3e0cc9b7e8c37a9e5ba70196f0fd2e530fb1fc283a4d68 +DIST cargo-platform-0.1.8.crate 11813 BLAKE2B b074b49e08b2b93e93e08276f2a79546fe1f9ba0a52b3b4ef0ecdd28fa3fe5e842c0291fed158a1a12b90804e0172d5419b7603fd0d5f87f062f44dcaf3428f6 SHA512 187acf1b8cc81078ede3353997bec9010df32aba82f56f9479d4c8eaa13436590a16f3ab6ea11ed2b31d1d1d2299d824d9ad10f04bf5281c92372cc8334b0dd2 +DIST cargo-xwin-0.16.4.crate 28603 BLAKE2B 4f2103f464e420d46f99a43fb176df548e904d7256a5d5214c75a9ad835375b6ef71847d94f77d5053edce16bb1204f15763f78e3762c981b9286b3a4c539b06 SHA512 eeab0052918fe03086ca012fb3db277aae967b34ae8aa481eddaaec783c8b3f8fc4d34b199e2e534e1f5e55c7f30be143d931dfc76f531ff81e1af7def2acec7 +DIST cargo-xwin-0.16.5.crate 28602 BLAKE2B 2077c64cd3ec649f9b74a024e6ea6818a212f12ab85301de462d556c0f06d959e7af3efb4a2d1ae2cca8ead95954c52b89b41dc1f63e8fded6a9a6f7bc1676f5 SHA512 bc1288ada6deb3bca456f5c382d4249c42ded462b9bb9f63f088553acfd3dd38f757ced4fbf1d77887ad3867ca10793a3ef8a97e17652869147fc37608ab1365 +DIST cargo-zigbuild-0.18.4.crate 38251 BLAKE2B b2e3ea75fd17c39320c31137ce0900088da4528ac5afddf5c656526615a59e586305a4aaa602773b2ff9c7bce481cd0c54c14074c8a1e6566c3d1221038fc41e SHA512 8bb30587e06e144177068dfd74fbd5c0a9b741fe60522841205e3ccdc89e4b050dca75bf12d2e1a1999fd36db9a12e53478acc0c60bc757319d507313d17acf0 +DIST cargo-zigbuild-0.19.3.crate 41006 BLAKE2B 655e209d108efb665df0aaa45806e28d10a9fd7a0b64c864c0c610b82eb5e62b6007593da04215cd4299279ed77ed5e227b323fa485369934733797183c892fa SHA512 0d26df1706ab21f520a29725719b3815e82bc92e99dcb967f2bc8e8a3d9da854469beb3e943ca9e23f72638093f21d488af150498755ad5ad1938c585960f741 +DIST cargo_metadata-0.15.4.crate 19993 BLAKE2B 33bb182a4fbf453be323cd657e0927d7ae8f4cada172c482d96ba959155aa0bd5fc392d4e0a6d4a869456be5de8756c92a4ee0642d60db992aca6d8adadb8f0a SHA512 dae54e7d21642a12fe967d832769f2310a18903a0a46694dd441974f037d8a53e148bae2668a177478b91629c5da736ce56aca3e140d442267ff0bc65bb984a0 +DIST cargo_metadata-0.18.1.crate 24535 BLAKE2B 9d0018e28a3941e269dbd30291054a882a960905a43d4818c874250356a6c203bf08ed77a8041f08607390b2a382864701c519d71a0b88818ee59c6322c74e86 SHA512 43f87d2b84597ec9a27e9fccf06ec5f2630a0147a9c85779622c25493bd61268c266643f8206a17d76a16329af85f0cc563a9af7e17ca77024c0eaf788555f7d +DIST cbindgen-0.26.0.crate 206157 BLAKE2B 4c435ccf9d5ab3cc036691cc51c55334e27a0348002b6303b11974c0aa4908b9f902577ca6e50bf241ca75816775e7bb33901f1f81e3d5293ddd2128b458204b SHA512 2de81f46c9c68c985241a349f13125876667d1460d3658ead8c4ee9788cd139c30dbc08bebddc172cf0bd4644f3f17c02cf66f2a3ef706c52366fdaf0f9d8059 +DIST cc-1.0.73.crate 57880 BLAKE2B be8d7a25a54afdd759844e76aec61526fc2bd5ca09480e6cdd3bdcf27e5f9d3a88dc16cbcbf54cd021470a7cc521e1ad468116c112bbd30752bac0d5486939ac SHA512 980f012b90c6410144f6de4995048337e09214f19603076db6d4edb88e9ef9ac9e8c6e25569f66c2be3a47e99298f5886dafc102e1a9122316179aa26bc1c985 +DIST cc-1.0.81.crate 66857 BLAKE2B 1f20aa7fe1e41b7d043242ed2e6b840ef7e764fcd844d82441d20dede2bac7386c8089e7dffee5bc22a49bfab2cf9f2c82757bb5068fdfc82610eae7cb2b188e SHA512 00878fcc5e344571cd8756fcd7e0a8e11325cf504eed09ea2ac890368c4d69978fc0de9ef99757cbacdadbf50faadc486d20640b529ac9a4963b3afd71caca6a +DIST cc-1.0.82.crate 67879 BLAKE2B 3b06cbe1516d4fe8291e1543b09d32d39a135c2352e545b64bc69fc82a40128a9b1291f20bd4cac6a3c37d9466093f8b63cae20663ad517bd7dbc380bfa87ee7 SHA512 27810ea12401635b0122e5b3a71367a52ca7040f196cb30f709e0b8ec0e717aeb8a89ef4e891b1c7c88f7cc8a1c35e55db132b728b0c499e0b683d5b803a671f +DIST cc-1.0.83.crate 68343 BLAKE2B 33245b33fa845ea2f36da36e3830ec835f937e4319865b357ee9d5ea29a0f9f8392eadb38bf1d95e3c15ed201e561acaa87aedcef744f8db3dabff87a96c7f02 SHA512 742a248c3a7547bb220a0b9c97b67a831fab9b4ac21daa08c85a3966b9fe576088def33e16132fcabec9a2828a6fc437088bb045bfc98b2cea829df6742565a7 +DIST cc-1.0.88.crate 75288 BLAKE2B 81c512bff79ddc40af633620ea440a73d3f7370c96878b3a84606ac0523f13a9ea756765afedaf2148344ffca3ce928fbb0678977273c918c21b4e3985507938 SHA512 67ca5820d36d1be38e56f54a0292d550c9c129d680611a60fbbfa458b8cb748e5f27c7ed1eb767ac3df41cd4e875160525b81ab624726183b1d298ffdcb87846 +DIST cc-1.1.21.crate 83463 BLAKE2B da552ae375ae1dd39e0ba40ad17c21c7edb52326e8d4d6c208aa3ba4ba4f65b87d36126f66343cd8cc85cd5123acbf2f66ebd29444d45d32122eaaf98918e707 SHA512 bf7b3a7bcaa1a46416a614918936bc047b9ab669145c954d92e81da6bbc5c2884ab64a95b290628922c8e1ac7ce0adc914894c8bcbd32a1516576ad6c749e0a1 +DIST cc-1.1.6.crate 81585 BLAKE2B 412ef9d62c32a42164f8c2b827c10f0d41e75faa77e6d1dd8515ff5ec43abd1da75bbb400460a43a252c93dd0a597c2e44c8e899a376d963f0d3727db7ca2c24 SHA512 ea8bd8150042268092360e6396226ee5e83ba154eae99d299c897ed16e8543fcfe3179e22b50b0497bcf065a16933f4ebf7edcae7e6fc8be3788f0ae7f61c000 +DIST cfb-0.9.0.crate 67837 BLAKE2B bab7c813d6636c6e8f371ea8a76ee23361b4f53235cdef2378ebfb9b3df30ddbc6d229a4a904d0711df5dca78711926407a0e2696a4e0d6151b5dcdf8f3067dd SHA512 6bff6dc27f459c7ae15fb537ea0218e17abe2477fa9aafad6b3d0b17773272db61df48ea9cb5055b35459373684b20a0bed031a4a53df42f262c08aa05307d4b +DIST cfg-if-1.0.0.crate 7934 BLAKE2B e99a5589c11d79d77a4537b34ce0a45d37b981c123b79b807cea836c89fc3926d693458893baca2882448d3d44e3f64e06141f6d916b748daa10b8cc1ae16d1b SHA512 0fb16a8882fd30e86b62c5143b1cb18ab564e84e75bd1f28fd12f24ffdc4a42e0d2e012a99abb606c12efe3c11061ff5bf8e24ab053e550ae083f7d90f6576ff +DIST charset-0.1.3.crate 14330 BLAKE2B 928771e37cc4f86f49cf09b671cc016cb662275799f34159dff9c22ca61a71d722f199ed36b2fadebde30b5763cc01d87bd6f27e70ff8ad357df10d6ddb652a8 SHA512 61166acd4fba3330c4c71e101e1993717baa448d91dd9773f7d58ac504fa4025322560ce82bd7de1b5935443f96ba84691658e5c982192196b325f52dc48f4b1 +DIST charset-0.1.5.crate 15918 BLAKE2B f79d3bb1c8e78598b6084761913dcc5e32b7c0825218845a5619a71987d005fe0c976f7f35064c4795205ac2339b92a58a3bc79b7554558ab7bd7c55ba81e2b6 SHA512 707e1b190cd98917d5f8a1b90c4375980a15afa3da6d7658ba76dff9c63e6a43666224555ba67da9b260619f70f2501ace4aec4490d5f12b1fdd912d033ff91c +DIST chumsky-0.9.3.crate 75112 BLAKE2B e74663dcf524513bf54494c62ad154fc3c3560910c429b91644f35327569df835c13645b148ec1b1339f78e9fe6ab3d5b83f10d53235a8e137756a548a9e6abc SHA512 f304bafa831c47fff4ede3b2e67628d7cf33d267559ff0f3eebba9355439f8bfbf08ed576aaaa1d51462114113ec1dc5d3593fa5a1510f6e2032da88d021423a +DIST clap-4.3.21.crate 55024 BLAKE2B 441333d4f256f34423b7fd991c1cf3cb336d4c124d15ec45f0b45959d12abaed1c397dd12dba99e88b7d8a26d90a25539cfaf484dfc9af6f8d1452d330ac3d09 SHA512 ecc4229f5f8f9890e023236de5ed1ccefd9d51a1d832dad59f03dc312d025d0e5d90fb4ccd1540a4f4077b6cfdd75f320e5688445105cf8ce4bfe20ea2d07fd9 +DIST clap-4.4.18.crate 55269 BLAKE2B cb5d4b093bb7958d013b28ee25f9cbf0479ada392b81265834d75a5fa2e6a4a687f8d4a71520d5bdce05785a874ffaa09beb5707766d59e70928dab00bc122ad SHA512 1f151864b92dcfcc69a66c2a8aa8310ce28171895698d82e2e69e19a6b51ed8780e5eaa77410df9aae2d17c9b45117b913a4c23ef879106c1b7a96182656ebb9 +DIST clap-4.5.16.crate 56627 BLAKE2B 83a6a9ad12b826affa68df179dc1cb534f58b6ae505f4794ca6dfaa8f8a9e33d93b9babd7931bf48bc13da31cb3078b442c4a2a2e84a8f2e675b5d620100c50d SHA512 d13bfda2c3f77cf194acd87763d5f2fea83ec2135504b173af2941547a7d3dcf75c3757532c60b53c57600bf4859395ddc94a7dd92b17f44c60d3e781741f928 +DIST clap-4.5.7.crate 56343 BLAKE2B e2392ddd11213c8410344c474d84bf40d2d5a0663d25ce8126940ce59085a84334223e92ebd59fc387b4d1334b8f8cd7b76eb15f916adc5ef59b9858929c5787 SHA512 f126132811696d5fcac0242264121a08c1f7c59b4830d73b6b95b8c5b31a2c11928b0d7026151a5d1a0108aa912d7c6157652193ea1ef5a980669bdf388d5bfb +DIST clap_builder-4.3.21.crate 161410 BLAKE2B 4442407e167c73064ce929f41b7fe187227b2cecce564211d9fc315d4ac23b27584dd18c11e4c00164f749d3e89c4ede33c599caf9b895bea30c65a7f0ddb9b0 SHA512 0cea697633d5911bd5e592d9b10871764fff19250f4eaa23f634594ff2223bd78d59e6fdb9cc7ec2b81815d1d4b5a2ef6a18855e7010de3c1e47790a12d32874 +DIST clap_builder-4.4.18.crate 163538 BLAKE2B 9991c1a8aba5feda466fc878f9415ad9b5922ea1835c17e1dd6c640234ee85e623bc556ba0e4edd84100a0879ae462028c74304465310d69f9d58e333c2ba8a3 SHA512 ff04ce8e700d8df4a0ae94e8341c3bcc1ebd415312e3b21d56e6beadf604aa5576641861506fa1c901a615a013e4f30bf8e6467889d637b34fa37ef22e2a15c2 +DIST clap_builder-4.5.15.crate 163717 BLAKE2B 795fa9c6de6a3f4d9a1288c3340613c14b11a5346e314f5f486bee76346f5f88396e54d95d051bd84184a91bb1f2d3575f870fca56a4b9b590ea2d9939beb415 SHA512 52efd99bce20bb8ff2187c4cef8bc27bef6cdc52598f00b47639b797683f18c76a79a6ebf34d1d250621a49cab0e9ec9e7824d323516f1ed3fa721cfd34cd713 +DIST clap_builder-4.5.7.crate 163957 BLAKE2B a1d6e728f05b7f7eab8fd9fc8dd0e25f8a066e0ba72ccd6084e747f5833ef90e98b63f4bb0b3af54b74c193df3ceb4eac63a45c9f3222570ef7ec85562346a01 SHA512 df0ef9adabb61538619d94ead0768fb8291cdef48c0cf47b323aa366fa2564d89ddf65cd0ef0b7162ef5e590be26a357cc775ae5278abf8048c05a5fbf58b5cc +DIST clap_complete-4.4.9.crate 37659 BLAKE2B 99de16ea4fab3996ed9e7d0855b0184ceb3c5740b690120b48490c1fe78115dcad3d8b52b3ffa31afb2b0e9f8e4c0beb8e331e4cbd5b1f688c1dcd4b49f06ab3 SHA512 79ca2717a7c4752959ca48c60e8e0751de67be1e40717cb336028d5edbeff0650cb3bbab8463dc6f227feeaac3f18acc249f08f26d1855055bae07758b3733d6 +DIST clap_complete-4.5.5.crate 38809 BLAKE2B 943ff061b229d3120368579dec89a3ffc0af592ec7d7d4cbc2260fa5c2435e1e1fb0e50c2f305f50b5899f93bf1d0ecb619602ac36b2790d364c656dc46b2f14 SHA512 b127163fa81c3934436481805179ae198b932ec3fd6bf0453b75c0d3672a7c3aa5d022411e88c7284de843c944da633aa566078714a495233eea9b992de4a609 +DIST clap_complete_command-0.5.1.crate 8273 BLAKE2B 84302d7ffc34d9e947dd141421462b2035f324a77a8c68fa342a49242b0f97e43afc54be90d7cbb2efb311ea7848313af3d98c572402e7b25f83c22ff1fce8c4 SHA512 0cbd75f41349c709440ceee1075cd209f927b928c665b31907caecae91ab0b1e00c0a73f8185df754663e4d079467c6312abdc175bb6f8bd58c6d783b371754c +DIST clap_complete_command-0.6.1.crate 7959 BLAKE2B 61bb266fdebb625ce3327164ab39d65943406fe9c101f10fa3a1f18d4728e0eeca07dcd8eb4e8f6eb63587cd1af86fb05beedf1c5b2bbaf22356f213ea738c7c SHA512 b364cac56e9604c7c06a84f5d687b62398f92e3c0407123b183d5c3846948a4a0975469326312ad57e2ce936574462f3dde61385062827e48efc3ff813185ef6 +DIST clap_complete_nushell-0.1.11.crate 32198 BLAKE2B 6a704251bfc10fa7fd113f7e82bdeb9655f2e23d851fc3d654332ee196214b179fa83ed6c57b436df247f6eb1d2feb28017090b9087b7b8d92283978e7ce9957 SHA512 04098511e19cb629df43509f2596904ec2a8690fa6bcf160825030c42dad73f77ed184e5a4dce10c8308b9718541540f10277b0ef0fee6b039ac1e7b482d3cf2 +DIST clap_complete_nushell-4.5.2.crate 34391 BLAKE2B ce7a44c4a9e3d577e014c71d6f8f6b16e192ae169f499973316f6f3c7febae59c957ba6acc153802bde423fd58301b5b5ef5b606e275bf8f608ad40fb192338b SHA512 1da7b7f01e948f4c055bb912426d950418f353837dda9e6bb8e249bda4169b29de2291173c9d0193f0c746ec1387ad8a893721f32125f14565948f2e90fddf53 +DIST clap_derive-4.3.12.crate 29052 BLAKE2B 501fb22eddca5b21456bd9911ad1f90ee5d5c918eedd08e2615d22ce58bb0fa5dd626b51a734f20b78411b9a4492ae63629131e0c2e1bd0f3eee21e5da3fb37f SHA512 a58e948fddf45321f0fcfe9d9afbeff42849da472fc4e4b15c31f46ffe55a0dba34d2c1d14e342530c1e4080c43de790595e4f3dca06cbb6a8a60f9e3cab3abc +DIST clap_derive-4.4.7.crate 29046 BLAKE2B 96ca919b8f9901b2e89c58ee8cf8bd3881ff715ac27999c03c867b317321e4839d9e923f68d411a05b45c34d54557af12b8a173f2445732fb6de16f30dad8e2b SHA512 4be40460468f7ce22906cdc9eea8d01bb07cb206d4ce0c3df2abd929d6925b175a49cf63907925ca16ae6297d6f4d933087fa5b35958e551117ec7ae050be167 +DIST clap_derive-4.5.13.crate 30132 BLAKE2B d5fcd2c5a213817165c61ba2071fc6424ce822e4881686556b8379fc71188f60d8c6712f6f4a8e5c8b125b58d7454aa9846214caf324fbc93300abba240bea17 SHA512 2dae32bffd91de9311d94e2be0d990074cb2e2edc832f422cd5e7c5177f5daafc0c335e74f865024c77cae5fff631ddaba58028fcfc24b203467478fd473bbf5 +DIST clap_derive-4.5.5.crate 30017 BLAKE2B 8525d8adba25ec0165936f72f78dec3cdffedc9de8e537b078944b1830640222013e335e86a2337ae9ea3b07dd655275705eeeb8c2155224dc0950ed00e47f7f SHA512 90c2110445c832d81cf66287ebe32155c6bd72a0a75cdbceef4e411d4b9d83268af244adab6755379b6970b5d40b39a9f89df9ef8786429fe73d95a3eee1c134 +DIST clap_lex-0.5.0.crate 11792 BLAKE2B 0409c9d957ea6a566eb8b50f4212702df038d04c4c38f7440d91cb4c58ec887940f0cf500c4c3949c2191399aac3f5cb1ce44868eac587cde90211d3e467b9a2 SHA512 0149ed7c2438a19b4857f895767550d783711078f07bfa9ac8ca531e06f51c7388110f4d558e30bf503536367cc370cb581e8deb6fe51f9b5460a334963daacd +DIST clap_lex-0.6.0.crate 12272 BLAKE2B 22aa04997fffa15a2efc7013ae27fd223c3247cd31f8fe96aafb4e87e3224f075e887df10a95a2da80b468d4e16088ae9f171ba6551c0ae06d77bf3b8920ff9d SHA512 3651aa5e27ed35b6b75b1d25fd9c20c26a2a6039116e54d84c51469087732a4f0fd71754326456b367e341b017d03749e9a6774cb7b62250ca8745f5af46574e +DIST clap_lex-0.7.1.crate 12766 BLAKE2B e0e3a1a4a65bf9df3c21753f9298a7461046e6b34c7a8d26521efc551ef3511a7d202f25ebdddf285ff68c4073364f48cf739ff0bda32f41d4fd0c87c4cf02fb SHA512 4cdede5eb9fa527567e9f3f94fd8fe7e1022d9e9236e78d30b3068befbaadedd778b5464f800e74bf187c44af9df582365f4d41a0113f8ab0fe9abc936171fc2 +DIST clap_lex-0.7.2.crate 12805 BLAKE2B 952bf3f3885ae7bedd0e8add236590da5fce72a7ccd88ebda063410aef337ce7ccdb5e5e929cb870bc993891610edc0197150a3aa82a62fadc4bbfd96324fcdf SHA512 a8726397e5372fca3389748efdfdbd016b6baedad5b4bd95f33e4e820d4f40e0b94c88b1918ded3678aecf23911028e2261837e73d58ba7fd6f091eb47267380 +DIST cli-table-0.4.7.crate 13195 BLAKE2B 498e7434639a4bf21f4b793def59e2f045f8353eb2e12ccbf8778a0a92196ed589ddd94e696a000fa7a2bd50470624f2972eb613cba538956e50c6ecaebc1b53 SHA512 2696d3204107f2bf104312fa1e13a92638fe9ea1894263cf707cfe3891ec083499b1b0594d8571169ca242abd6a41396a88ca41dae8a3ce7f04365292158a87b +DIST colorchoice-1.0.0.crate 6857 BLAKE2B a0818be1299717461ffc1bcfb6fc53a0b3b645aa8c45fb72e045cf2d876fa207948610e58d6a837aad24838ea9616e80b0558ca3eae03fdf9bc4c03a8e5ba52f SHA512 53363f2889cd8e8a3b3ed10c48356896c0daa72f3c12c9c7804707ab0dbc07c0e34ef52fa4f0fb1647311ce5913168c1bf62c2407ff86a33f765a9e6fccad551 +DIST colorchoice-1.0.1.crate 7895 BLAKE2B f1c841e74f01f33fa83cf41c5f0a1286ca3899239d9a188a838550abde507af374a4fe3e85934d10d28bd5eae2c7fa1f662307bd46d5dd4daa52249cb64ebb5b SHA512 3d216ba46cfcca5c52a56884ed09fe7d6d350ccb44144a60c75006582f7f9a28df21d44375a8cb304c721b9de615875675b3a03c485eb209b2a12d745fa609cd +DIST colorchoice-1.0.2.crate 7924 BLAKE2B a4027d5f870b4d9a718ac3f9d89ce04e2ed38406658c4a55ffaf39ed0cb1ce7e1c691eb56c66596b519ca82309e8ec7eebac65e69394cdd277f44f9b6280d560 SHA512 f34d5f66f84e90f473b6b9a62a61a59575e712d3e9b140324683f80af42d40c1d079701aa2ed651d0dd95a5ac8838e1f6f6c034e2adef79509d32357b8093117 +DIST configparser-3.0.4.crate 24680 BLAKE2B b9f6552fb57cf175cc0bd61138e724721ef53609ff86033273af772c48270979a76e60c97d67c40ce0e1d326c5e6dfee9113379bd3f3b6d37b1e290be97950db SHA512 aef273f5ce927a137294b3a6f1c505720ff9029d3c163785287a43a551ffeeebadd4b7212075524a836dafd9d2eb740046b3eb4d33535d20a98cb77372010d4b +DIST configparser-3.1.0.crate 25473 BLAKE2B 35bde987961dd7b7071ad17a00041d98641dae6bb57b2d42fcca9484a8237499502552b837b7330dcf3b2fdc7fcc65a3aa3c319e85798a63f02e16adf36e6aea SHA512 89b3b51a60793b8bf71ffc8f5a7c098264d1111db644fe4ae54c797af9c712359aeb001eccbdb41569a63d9052efb2f8d1b069842da0ab63fbac9a3d7e1243e2 +DIST console-0.15.8.crate 36364 BLAKE2B 467de2c2fbfe31688cea20b338558ae9671e50ba1fd07983d21f32d7eacb73e565ebdd6ec5e78b2ae04446f09615c70983c0ee534e25ca5a28fd1b408acfdf34 SHA512 b05e49ed145785e29631d481885788f0cc5574d4d7c4d90280dfedaee7f8c1515072c9c4cfe6bd2e017230cd228157222af7e7d41a9fce697cd1888095df4de9 +DIST content_inspector-0.2.4.crate 11386 BLAKE2B 2393cf83b2dd338ded7f5acd695e05a4a08fa639a52a8042dd0692be5e959cd1cc670472e25ca696a151d161c821eb899b2a950c74f4cb5b880bc42bc53d1d57 SHA512 1acb8b4f12ce3479f5a60b7b6a0c05b86548591e488e7be529c4a2f9aaa60a76ed07e7ce1e557664d31ddd9964e7f73415ad667cd14ada919f61511bf486ed6f +DIST core-foundation-0.9.4.crate 27743 BLAKE2B 5b695e671cc833170bc6bad436b2d0d8d386ffb8181bfcf2e92a1d93cee67c3ba1768cf57064fb91b0897c6aec1be7db40b5bd256a052c1bdaf872ec19f6e15e SHA512 82d0878a1b9e3d56b3666fb5a78f92c6f7806d01665c242c06a640bd6b1fd36260211e92dc05e1a16d1430622bfdd650aabb0b5bd8e5592f74abdcf412448e33 +DIST core-foundation-sys-0.8.6.crate 37629 BLAKE2B 683d5a84b6a3816317f87359532a8339f08bb4043f1d70a8588636eb5dbe6ebb3843e2a12d9a7e5fd1637a912c52a5aefbb8d44796330b09593e7adefd3babd8 SHA512 24a8958cb16b081862a9000affb0147b8b3be1a664b834c3dbddbff03e709de3f4060ff4800e5a35453f4392ccf33168e8b864be71b17be38cb264a39b915100 +DIST cpufeatures-0.2.12.crate 12837 BLAKE2B 5b518c58c548d9116f94cefc2214fe2faf87c3aaf3fffbb0bf4085f75372cf7fc5144bc3f827101a3a14a51363d06d8075db94ff5ed853ab2ccffaf597728093 SHA512 52742595702fc3371d4126fb355f3d7a6da514a94e43170f1db041cc6c560027f92115eab7846131dba1018ca5c72003ae36f945c1de88d57a0e7f66331623c6 +DIST crc-3.2.1.crate 15070 BLAKE2B 9d5f488b57bc232528cfb8d9ef33a88d25d904395dfac8dc10e864dc0d6c89e576585195a20db585fe358859ec50afa998562ad6becf6fd2e505f3969eb36ed8 SHA512 64b7272d8cf55efe9768f9f3218f83302ccb59458a56fe3b7b2de1a53eb5a3b57fbf268647fdba5b230cccdd4058462ba583d76870ba12cb1057ac2787f181db +DIST crc-catalog-2.4.0.crate 10155 BLAKE2B a9c3ef81871d72635addf1ded611fa6e963b9b128dda198eaa3a256512c8759608bae95df95524704aeb38f81e2fb6c2da2e29e306a8ed3dea595e63cdf05638 SHA512 25536456fe71c44fd8ec527299339c1d186f6e12f1f90142de60eabce337d836c2497ddd6307473b57a6cc720cfc8e29b059f378c70b8165bc171420ccb40a29 +DIST crc32fast-1.3.2.crate 38661 BLAKE2B ce3762b03d24d5367d89738991c060f4b3af7840e0a7ac7fc17d01ed438caf964bbaefad0fc4d0c438dafa5a578429ddd353c71197f8b54b1ec441395f2f7ee0 SHA512 a683943e252afdb1b9d626a07533ed11cf7a63af603c19640056c5d2b9c884ad9aff33ac54c0853ffca2f6cf94b0730eae6c05abf3e53e55e709d180c8152357 +DIST crc32fast-1.4.2.crate 38491 BLAKE2B aaa3acca66e5814a45f12a90ae09f6ff5fc14ca94c8539184dab6ed928abc68cd1d37e539c268c1effd50ab3af20de6038593fb9c6bd6a664785dac52f6939fd SHA512 c7608d33022062e217d3576f536ffbd51479855a5e5874529c71db2bf6a937ce04d814c39cf777309c38445393bf43cb9996161947e28738abd432f11beb7266 +DIST crossbeam-channel-0.5.11.crate 90434 BLAKE2B 8666f039a0e4ac6f0f8be2d08ce3349d8ad4aa7d0f38c638dfa6dc6a7f30a1629e42f87757d9e054e836941dff6a8efa53b5337706bc5958d33dee61f38e7bcd SHA512 1d37bae1c946d402c1fce37f22a82037d68896770757aa91d209387f947d39c514df52e0ce94317141513784511ac626482f16099cc3b62ca28a52f387b69c71 +DIST crossbeam-channel-0.5.13.crate 91174 BLAKE2B 7a9aed6f4922c1d10e4ae12508a03dc7daca773adad6a317c4ea38e544d7c28c56a06623d958aec540fcaa86fa9051a1aaa2c859dadff72873f18f2f3a951449 SHA512 0f31223a7099f84e39e6b76b19cf26736e0c3907fffc2ed3eb0012c7984b1993570bf6d155eba5bfb82897ef0e4fc93b89096071410bbac256ca6be9a9568ff8 +DIST crossbeam-deque-0.8.5.crate 21726 BLAKE2B d97b35e8e8858deaa7fa9a836e836d02914aad29e5c34ab121f52ed65e95213cb2574df82273277365889ea771f04eb40bb2439347c259979f1dd6d5e9853bcf SHA512 0f0c9745763ab156136227cf1415de514952a3f8282ffe413cc249f9f4b345b029940e6a6c87b3be8331a7c783655a35b89c7a2547360ea5ae10aa64ba7ae864 +DIST crossbeam-epoch-0.9.18.crate 46875 BLAKE2B 200c256cad6011a3a14c4664bea6b150fce72d561c4fffc387fa561b08c0480e8756bf51c14874c5fb19f427424547f72d2cd7dd6f56fb8b6666a85f8d52bfd1 SHA512 0a8a199b9d77f4e28e91fe0a0cbff7e0dec58cac283631fd972477fa912d2f6ddfddaed2c695e4978b01cb5440b702822af6333e7c3dfbcb9a2c2086999516b2 +DIST crossbeam-utils-0.8.19.crate 42328 BLAKE2B b2846f569555818fe7a3ef4aa29f68c638f933ee0251713c2c92624bee5f8013def5527027022963f572815991abb98d5e68d0fa00f478b2762133f84ffc84c0 SHA512 6e742fbb0d2a6371db87e81f8ac583259530a288237d0e8347394581c60004703a822318ec945936c410bb44001b115d8d986bb264e5b2d8091bb63a8edd93a9 +DIST crossbeam-utils-0.8.20.crate 42487 BLAKE2B b50da06721cfbfff07825574feada8a28d3814edb218434288683eec31bddabe2ffbf7e5ef1281ee14a8a77c56db3b66f3c5ceabaea9c72317c1bd2cecda0c26 SHA512 7175eadf9fa7c526fa11ff87e40ff203f0e7a4bcec15cb972f924f3c7ff7cc20b6e2e8dbbc1ede142a0207cd2baa4f446deb25d825d28a54cbd25c263701bfaa +DIST crypto-common-0.1.6.crate 8760 BLAKE2B f2422bfb89c15d47a8f91c8f6695e05eb56990a922e3cdf3d426044736f9932324c0d899a151a6df4d6683e6a6b21659c657d3988734014c02cd854bb4b924e7 SHA512 471dbc43f517089d2cfe0868e29510c6ca579875b3bb5d013c70796db969b609b6c4bb35c9a07b9a2917012dc5708b717d48e317a20038adbe7e7039bf3ada6f +DIST data-encoding-2.5.0.crate 20632 BLAKE2B 16ea08dd12f09f2e6f8ba2910b3db07d4e7c9916e6a70d41420ef1a0e5393284b49787c47af0868bceb7f5d3f1fadf203f5a547dc8cb97713d5225dc9181fdef SHA512 b1de8bcfd7cfbfb988091fdb550eb98dfa5739ff58c4b789663e5db0d539c9acf145ccd72d87f7e1cdefd09d5771772d131d2b2e2589ac8f0bc6972c801ee0ae +DIST data-encoding-2.6.0.crate 20769 BLAKE2B 9d5713e63f6f6a4d6e5324fb0be9308a231ccefa20d69cda9e19609a2250e2cd72030ec28309068f71c932327a3ef680b749125658e27d35273354c3465f9931 SHA512 a685c7bbd251a5738b27ac3ac8121a0db049221510c99e0ada6f245ed7499d04ec29d725ad01c688ad283e3d2d5aae0751685c804f6d95cae84e63a160d04c9c +DIST deranged-0.3.11.crate 18043 BLAKE2B 738d5a88732e227bb0e0d33c04ab8248a699c7c499100666ffcd78673d1f38ad2d740222ab405e3eaa7a0a6f4596cfef90bd581a1baf77c954dca830c22e74f9 SHA512 48485666d3e50eb7976e91bed36bddbaea80fac4ac664723130069bd7d17893b6d1a2b82a4c3dd61677162e4305ba5ea8aec7bc2793d1b8b92dd1666c204fc43 +DIST derivative-2.2.0.crate 48076 BLAKE2B 56d27e27493c3b818ad45703efda607a0a0d9a48b0d43785b6a013443b8b964b67bb5b5284d242358415c5fb81b86b02079ee7c0595ec07bc658240eb114b887 SHA512 3c65ecdabd2dc202be3d83b06f96b6f68504fe542ede7e2285093c6d360a33ec76a3787c436c6e5ff8f59d430436a4b8ce2f908cf7b2b08cd8b0045de4e5d1da +DIST derive_arbitrary-1.3.2.crate 10614 BLAKE2B df96dfb9000a794e3ee6e633ab527621d321db8006221b482e944d58d4293c3f87f6808af4784c53c06b28f3078ec9be6860e3496d6af044ad6d71db35310dae SHA512 5ff36cdb5fdbc1120442571b21405bca9dc3e7a0c0d6f0b4996fc71be0553e1a8cbf2626457c55198ecd9c66d18dda66909823e7c6f1f16151b5d05e1c69d201 +DIST dialoguer-0.11.0.crate 31286 BLAKE2B 612c7b9de482b48df6404ce31b3d9a8afbd1c8c42807f2c3bc343bd3aa16c359abc95bc879304f29c6861c93101833bf5da036eb0fe85f21be50fdc3a771f447 SHA512 7124e9943dd4fd4403200357b7d26683e7ea709ad9b0251af5d6db4dc8da2a476c6b89e7413df3a90e4279498bd54b67d8d0b161b0e5ae8ebd0bb5b5276cd612 +DIST diff-0.1.13.crate 46216 BLAKE2B 27ceeafb7afd45eabbbe22d1f05667f513a6062762e6b77122e267282a8f2a0bf96384989508bf10c9e13af4856bc9f58f09b10055d6fc2c32681e288ffa9f9e SHA512 45e259c9fe7c23bd9e9454891b42d4aef6d681d35ee039d21fdb05ae9ed5856161a40f29889e7880ac2a2daf85f1b7d752d213b4a99a1a74ed2682c18a3ae7fb +DIST digest-0.10.7.crate 19557 BLAKE2B 61e69d78cb8d6850ae26ad7ff2d52dd6dce820d8c621230def11cc0e8aa6d883a6e1b25340fb45748db52a8ccf3c8d36a8aa0c8cdf4d4eeb4e3f870d86abe09a SHA512 0dd8c012468ab9011b89413ea4d3647d95b1f683b020a0e6274c95ed5148638b56fef19cd9044c837ad53715b582b88eed277fe96e917c27c5d7abdbf7c3794c +DIST dirs-5.0.1.crate 12255 BLAKE2B eadd38e85211ed5aee7fab964e90342273320644c36262aa7b436e493512851a4751a09d22aa8bae0495f4b22df6e7395d13715ca8b8c6196107b1be03af9328 SHA512 cfc329518e85a25c296521b9aeb6e5d5f60b4525aa786ebfa8b9f198446a1ff5892160d1bb4790d7f3fc4a0abdb5921b2e4896e271a3fc3a3225897313b77bd1 +DIST dirs-sys-0.4.1.crate 10719 BLAKE2B 30334f2192698d7d03bd4e8bc8a682482da7d13baacb8547a132f55019d3727ac35579926ba4367fe0a5b7fa917945abc03e010cb7363683753c87440581df42 SHA512 53c7c8bc76d7211d08a0e6b25caaed12eeb7283cb4b352c12311db3c796794330943259a08e48ff9d3a280917920a088e5aede32677a4b2f9f819c2dca6adb9a +DIST displaydoc-0.2.4.crate 23200 BLAKE2B 91b0ae7018109d407095060b6bbd6aed1cc21120bc30348e8b16b5121f7c35ab72b65e80bf97dbea6cb4ee6b4d5215e8e5c4374f92a569697bc9c862348620cd SHA512 a1de2c200584bfac640f8b84b5103d8687919cd29f59a14898e98d480f476a8e4dc06e3b929af479d536cd02186e2a9be72e6414338bc117b97bc0d160029592 +DIST dissimilar-1.0.7.crate 27588 BLAKE2B 499890812558de9d8dc2a43b8b3430106ad8fd5f8593aca6de08556afcffcbc251cfa02c1881f6ea4edb164166335d3c8ef3a5cf2d7e51f4e1c86bd2ec12ab85 SHA512 f3e21500d19e030c629b1ce8f809cebf329514e4f901baa443ca2f93c4dfe7d49342c998216e94560c4fde4415c252dbf213ac7a6f4953a229ab0808d99b152d +DIST dissimilar-1.0.9.crate 27652 BLAKE2B 2a5d4be38f836dbfc4015c4173156ae1bf769ab3481a4e8ed2a9c2349588403512191d47af7e4210fff7d5c6da40a513a3034e0fbbdb8cdd4bcbaf329da203b6 SHA512 12d9b849b7ed14a4106123ab0a23c96a9f3fffc77eac3d780d0185eed9a6b259f64013460d22a34b01696f947cdee8f12f6a21a7734ef8fa52e9a84c9b60b36a +DIST dunce-1.0.4.crate 8034 BLAKE2B e1e7ffbcf1e3632036c03303ab46fc37b2b0a991598790b2dc65d7a61341a78bf555230ccded8fbb87d6288282af3ed2a8641212a0f1fab929bf99298e878b6b SHA512 f57d9c53c177bac8e10a4b56ae421c604085aef0f264b8d6871abb7e1ff713b55f396c5c5f24422763319c504c6ea6a774416af1c2ba23ba7b67b2282f6731f8 +DIST dunce-1.0.5.crate 8244 BLAKE2B 1499ae0bb3d34e8d42e97eaf551308efc95697366b804dc83c51171a939d45bad46fce9f82a39e17b6b92fc833aecc85eabd2104823c7db30396833388125728 SHA512 36d7d75217d629185a9a9187f7d2e2dc346a28be0ad1c21b1b6bcbe3991e9cd11797e53d745c0b3b5ae94cf1e4cf141cdb2322bab86d97cc258b4145e3b97a56 +DIST dyn-clone-1.0.17.crate 11848 BLAKE2B 1f90492639630036e1e877537328e46ee3fa697d85b2f87c45990d4a51cc900a6f604d077b16575015bbf0a970c26f898226e87e6e2af82d624f5fa565036617 SHA512 b51fee8c4fa3c6b0bc677e9997d4b6921bfee9a11e369eedc649d19eb5d95d7872b533b37fb1ca842c75e714b46afb1231369341c45071db94f09b53e37e03f6 +DIST either-1.12.0.crate 18974 BLAKE2B 9db82a8eb351dbc1643ccbe304796610f6090b263d9a991b4d7308a699bdc67d25096ed1e923f521fe3dbfe9195569c1297b46a4b1d0b74bcea4c11bc0a2c388 SHA512 88e1ac4053c39740cf643a8fd445f2d939a8398e952b4b66ab38bb48bd54bc7a976967c4bebab36fed66c4f5fb76082e9c6d40e146914283fca28f31af0e0138 +DIST either-1.13.0.crate 19169 BLAKE2B d6223c76421babf163a694aa513fe07adcf4cea329872c02f5af5956e89b2c353a899f5708e5a2924e5a92d871ba748490350ba30c17dcd78dd4379e229f6e11 SHA512 72e803079bae621d282136ab1e423ba71415bf12038b6f386f294cae68a67ad9ff16e4fdf4344eb3fee4418e853f9cac344c248f6befa3006d1c954668b36322 +DIST either-1.9.0.crate 16660 BLAKE2B ad61038bfacb16f678fff5dd9ccf8f345e1bef18bd7aa0aa9c99d44abf8428939362f32fc8dbb1b60ac56016e0096201071d0bf8c0431b660605d0dfa97da466 SHA512 4978d50842386f51e31a47ad037d5e491106a668bc701bb833e6ec3998afe3ebd80efddc47756b2f300f534b39b26fc01386dc878d3b02cc8c1fec6a474c2177 +DIST encode_unicode-0.3.6.crate 45741 BLAKE2B e1e3792bc2bf9db7df33a516d0d755eef5eff1249aa9b2fd7f0dfcb155786c566fb619c9b2d73425a8625c8593988b117e9676c341f65e8795ddc838bf9881c4 SHA512 64193d6ac75f66d58ed864169b5d6228ede36dcf100614395e086bc8e847a3ddd287734d88e8ed50f38c679a99c80ec68449175a67d8ee03b02ec1cfa9d55e77 +DIST encoding_rs-0.8.33.crate 1370071 BLAKE2B 0e81419086ca6e18f2aba5194b87eaba49ddf20493fd6ee09d479db86306e39dff9b23f399594afc42f1fdb33855e070beaa1871794dc0b0371c35d296a6369a SHA512 20d28a4c0ff0710f911f510be56c2bc5e7514b76d370493d2b89b7f25d1c0cd46ffa64862e54fc472f07f928a2cc24cf9d790a37751cafafc81f263705aac4bc +DIST encoding_rs-0.8.34.crate 1378166 BLAKE2B 528692170cdb1d74ffb0b122a5aee61f50a2a7e4ce6db049ebea4a185e5c43d4ed99e515f08524053a110e061f788f861e62e0b04eb016e7a9e2678235a04577 SHA512 e23b87003814dd6e7e17924bd1f53989a5008dd1da07baa23c40d2a18dc1ab2d786d61e2c304b3f60e73be5f180ae2deea3b4499c0157b6afe3c9273d2f739f6 +DIST equivalent-1.0.1.crate 6615 BLAKE2B 302d78069d9df05e78b53f0488a9e4eb98fa2bc1e21893dc8a0acf2234347ba7c4df4b9d6b380ae77d8ffb1074b9c790460fe2dae47318aa1c4fe4208244540a SHA512 b2bc60e804c1b02c461dcefcfd60fc37145af710d183ebe65f9a4d63f2b2072d23193f98dc550a9213c7fdc6a2a837af23b04a89294ebbb681a4aaf5d5031140 +DIST errno-0.3.2.crate 10424 BLAKE2B 3061d5a5abee015bf41c11ef31dd0f38a738c51992e3bf9f9ec98f67a87b88341c97901211718a5f103b8cf021c875f8fc799fb217ad69fd27371326b5aa40e7 SHA512 b728704f11cfb2bffd421ad39e7bab79b11e548e336e9dd1cfb902bdfbb78a8afb102ae5684fbd6ac4b01b12603a1011a1faa21cfd0702bb25a300364b17ff84 +DIST errno-0.3.8.crate 10645 BLAKE2B 4a7af10845f11b3d8f177a75a692be468e8ef0ee53fb84a4d212335f1499456b6739a59af260894b5c3853d3bf21ef3490d1e3a613305561203ca334a636c3b3 SHA512 29753c421c6f929760cd7565f8171696e4f70e677654a7507253f4fc495edbcf214ace27be46bdfe5c1a0d782f4b688f591476e56f4a1096471cb353c643328d +DIST errno-0.3.9.crate 10690 BLAKE2B 8deb19cf0c830ff2adebb733ab961558cb4463f256604f9c76d5c5952f34a79b70dce47e28f68f459977ef34d4821ab5d0f7e79a7a110693700f80b49ba56651 SHA512 777fbac5730d420d58275ef63b7579997d8e6c72106d483ee1e3b1f1ce3977f1f66c56870a05acaa4cfacacb820eaf963e9c763748759cff3668fa2e6f89f04a +DIST errno-dragonfly-0.1.2.crate 1810 BLAKE2B 781fc26dce5c33d83b9a1fd9be2b2ce9ac2559aaa858957ba6777e143b1e44cdfee48e1b47e3c91a95075a51921d1a421d0b45eb3d8de827cf4dd0ad744a7d8c SHA512 f853f1e1b8dd0f359a8f9a0399b3384c1103cd090d96e2b2204f91a40d40a9eb99383d4aa6a11e5470c51557afacf452d4be2049600d4235d27f59870fa3b916 +DIST expect-test-1.4.1.crate 13530 BLAKE2B bc83162a09c2493dffd45d8d8bc11d3ca86ad1d76583073792b411a5af39684d0e80e5183eeb3b87f7001cde46901b280b67ee186283d23425bcfceb6eb5730e SHA512 5665e7bc640fe56f1134fcffb9ac80e5d6df820c679b768a0d68d58198167d3ff0893592adf88299564037ce72a198c6c8cdb33f83683ca5225e329494a2ee52 +DIST expect-test-1.5.0.crate 13574 BLAKE2B b5b2676996669436fc7f25f251d339f97ba78d3129eeef410bf563527bf73f7153e6224c747f5b9c6b605a8a4f2a2022bf842f840bc353f6d9e99c58396fa005 SHA512 909b210b2b787d37a7a1c203135f69ccaae28b37296ec025893fdd7499d18b8fb29d6f40acbc4b9d4d09732f5254333de5b21d0db5a106e851e7da57f9087ed5 +DIST fastrand-2.0.1.crate 14664 BLAKE2B 7a5812153500170dcc53ca8d66384fef46eeb5a8f970be43863f22f82bf427672d07cb053f4e04b0fea358ca89178399871235680f57223b8561c07b8d21cf13 SHA512 79a1e1b3f39264f037def236afbd87b732f5e0a2154b1d9e721b3c7990c52be45138320e2571fe628f482e0da7e3cf867abb745e3c277b19015fc031fd4410d9 +DIST fastrand-2.1.0.crate 14907 BLAKE2B f96c74c1da31bae35e5ae0a557b3cdf120099cd7f31475ff6ce0eddfd8d30baeb025cd17b661f452cc4d3fedde763621301545e28efa030b3be21d1d9ba8d0d9 SHA512 ce776a3d0fbc108017c93ce9bff7c9e7e65590acb149dcd55c2f349d2077ffdf5ac6427753732f60cd7acf141ef6f89359b2e7d9368016be53b24e8703e71104 +DIST fat-macho-0.4.8.crate 18658 BLAKE2B 61432b0a49b9e2754222b8b02dda8fcb09d955627abcf3895ef6d2049ec6e2d448f3f2617db9dcc431ac38e56005acab7940e8a4c148be5c9f77f7d51ddf748e SHA512 159bd21cf1f321cc9bb56e08ae561d6a00e0b83de6e4096365b8ce5c29a409f5312a78ec1c5122018f9990030ddc1596dca1ba56997f460f031ff8518025fa4a +DIST filetime-0.2.23.crate 14942 BLAKE2B e4d2d9c11745dfa5592903f3c3c6a9871292a02f9862607b610ead7562b5d1fc3b64d37e779cad0630bde8012efda72d86af5e687cd2ef5d3627d8a89bca517c SHA512 8d5ac82482758577d1d0669abbe7b880efc44958687bba745c9ee4a5c16bddb44ec0fbe9c29cf424e7120905f3c3da607f3a7ca1e50287154c0475ddf2148bf3 +DIST flate2-1.0.28.crate 73690 BLAKE2B c9f141bde0eda6b9c42da0a3ed69322c12c6c29bc522131f51ad56f6e2758646aa5585382407409257a8301f5f07a1825d150838bbb55822f2d49037f6279aa8 SHA512 9db6f3ddc4e1e91960b07c08712beabd911b297d93db8be3ecb97a392a4262e608c75ed8e9e34d87d58c3e67d1b7987734e14ab3d45fd837a2767e8016380284 +DIST flate2-1.0.30.crate 75511 BLAKE2B c25d9ab787ef60312523d80cf277bcaae16c7e54b1deb0fc8723a3b22c2586092343db1c538d96a37690d21e52ff822a38c90e10bc554fedb75671fdff6df309 SHA512 21528f80c1709cfa764723dce012903581dbc2b63ecad194ec601fc75103307e1b2ef17479186ad895ad957c9a33c6fd666b2981382a8a68ca78dfac7cb5d578 +DIST flate2-1.0.33.crate 108838 BLAKE2B 9fd23b3b0a75c29f750c873f74de8565f0d8f3a574c7d28e11d15e6c3c4686c42ba98b5769a08c21f3b9c6ffe7140196c3e7001153ff5a046ee7af40f7f6d965 SHA512 59a871137518586f1d66810528595acad5ca763ec5acc100098a372194f55f33b48e59c0806fd237c644a6d797b5deb26c541fa871a1194ee3ac725da3b6d134 +DIST fnv-1.0.7.crate 11266 BLAKE2B 81da85889c91b6567e0f555e37dd915f1bd919719d1ca10c31a6861d7aec29a49ae9c1e8bc500791bf9d6b8dbb318c096d04872c5872a4b1f7d45fbd8e12842d SHA512 2195a4b34a78e2dd9838caf0ee556bf87cbb4a8ef5505aac663b614eb59dcfc0c40f432463ede41ecca57bfe7711f72673d39a85fe03d426f1324097d5628334 +DIST foreign-types-0.3.2.crate 7504 BLAKE2B 520818b702d990d296ecd31a8646850202509ccfa18edd0e1b260289619a6c351e758f317ec0824bd76eccb209b6f087057c25f1bd01a47897715013dd834867 SHA512 bf27b8243ed482c202d120383374f19ff09422535e24b9c1aebccc66529bf300ca17b8bbc76d67f98ac092e614497afe3add9dc68aa69c93074df05762f91232 +DIST foreign-types-shared-0.1.1.crate 5672 BLAKE2B d2e42e04b6657e7a69fe0bd20c672176629c743e49a55fd007bb30e289710b70045d445ae9cae0eeaa747ee708c90e8abd9b5fc39bad8ec0666befe1b696d4f1 SHA512 bafdb2143e136fb0818e2ffd90b5c862b7181647d6568947d4e4531012bbf7a57b597221ec7056c1b562dfc0c3b5dead26d1a4111ebc15e7863737a873518a4a +DIST form_urlencoded-1.2.1.crate 8969 BLAKE2B 383d3a197b73fba199220b7708e16d770591ac16725faf4efc1a8c230c569c381870d4a11b8fba623e761e68f9d318630b22101d461e67dd26c67e13a73358a1 SHA512 c65104e2dc08fad572bb31f981700fd43dd29fcff42b01c7ccdbd3d4c23dec12360aed3f1b5fc4766fee386d418a65349b2941b8735f788cb0d35d631a6a8dd1 +DIST fs-err-2.11.0.crate 20449 BLAKE2B 8ffe7c49f4733edcd30ade9b75064e9fcf4ed1c87620d629fcd44dbf87e85e28d23fbaad05a50d8baca877f3eb9e088d8dd744d2ca092c443735fa7129609c9c SHA512 a8bf948b94e7325c583035a04d30c8ecf33d543ac366a550d757d65a0d7575d501e01dd1a80c8b0c278f80b9f3298f8dcd03c3c636810fbfe6a4a910ee8915a7 +DIST fs-err-2.9.0.crate 17662 BLAKE2B 9919c253ff98280eb3ae8d700ba3f878e2ffacec1d3ea69f0445921dd4084c67f3309cddfc2c4e9ba42cc9f64e201fc88313f517185e47f62c3f3023bed62e96 SHA512 b0fe36a1158a1267a10f6ca66f987448c2fe05dbc26af67cf92e2fff5af210312494823c201156f1029e3d81ec4b075a63a51770e153dad3867fdc6ee1d29126 +DIST futures-0.3.30.crate 53828 BLAKE2B 4e595639500f7147ceb994359ef1656ed096ea679409a5721c05ff84ba439fe4e82563a7cf8dca9aed4cd16b03e89ba1385b0a34feed9d4923871225e131b91e SHA512 98fc67bf1047609c8bb0763c00ab9cb39b6a6d0cb7d993bce4966ddc2492a6578b789e98095981b207ddd73ac4b1dfcd5224b352a0e970eed347537c6fbea43e +DIST futures-channel-0.3.30.crate 31736 BLAKE2B 57461dbb723fd53daa07b2fe6164125508cc3901e0138d2a60da5c814ade415a3611baa45c71487f1853812282ef358c132785ff40c630408e8544d57eee3483 SHA512 689531748821529c528772a6dd0f27362078ff5803d2e0b431ee5a0ecf8787b5a15262d65d52f48486ded46b88f7a9c477ad95cc2c5a3e8f5f9b9f53f367832c +DIST futures-core-0.3.30.crate 14071 BLAKE2B 76a9fa5aedd0d4ae8dd9db9639839b6b342125759c1b9f9bbf58aacb4ecca316ff1f24ff8f3c15f559ffbf974e4c2cd02a5418cb4c4d7612dac8449c8234eeb8 SHA512 3c7259ddacbe02e47a84178b75e5f13523bd0c8f8bc0b2375f7ecca60b7075695ee0a5cc4e1c1de26665cf250271173be803661e2f2f53e2a3b96380a8efe7c4 +DIST futures-executor-0.3.30.crate 17744 BLAKE2B 927abec40eab31251409149179baa95a8d025f9cdb848afa83f95439c4768abbf6da8e2163291a086ea0b83b0b650d1e19cb8e15f70369b70efdc70eb3121f6b SHA512 fa65c038e5eeee695b2673cd65cf7529713bef47da373290595b554bc287267ee5cd015ddeda5a22169cc8828717987364584a91a69685cdbfc0fc779abd764f +DIST futures-io-0.3.30.crate 8910 BLAKE2B c9af4290f45a9fd0839e107fbdfa4abff4f9077ff45b61054670419076f1c4508d7d560d4d86f8cd7ce146e436e531b9f5e0abfed2c4f2406c57be209cfdd498 SHA512 077acf5eab1101917b5b4b4b83347d30d533110d9a34c2de6db1411ffae0f0530f457033c5a5c14249119e89375c9f12127790b46e486dcd003a12a6fad48bc2 +DIST futures-macro-0.3.30.crate 11278 BLAKE2B 6311039db4bd31242e4f45bb7c581bec28eec9da850c47ffd9235c4baef5e5f1c72155f49573b2dc942a9cf246949b79c7d35200d04f91a13b0205cbd33d96c0 SHA512 220b5cc61c744617479d7e8ef9888785a17b9bc26c517c9c4445a39e8be21f111f77e53bfb3d143df18dfde23feccee17e349a84b897eb4d86f94d7ae4f714cc +DIST futures-sink-0.3.30.crate 7852 BLAKE2B dc768e4ec4c9f9dfb22a20c1c977401d859072b9222e6f77978332f495cbd0f764b175a679c9d7c77028d7b56cda5e2d86188ee979c7f323187defa6a0485ce3 SHA512 1c198da8f4118d9a9ab2b597e3f7b4e1ac7094dfa547bb81f3c4148c45216ef55b309255849174a517ebddba6c874283425f1df6e56e2ba5150af091bacf46a3 +DIST futures-task-0.3.30.crate 11126 BLAKE2B c2ded9b9b709fc10c44cfeaa72d4e7477e43331b14f3e72433b25126fef93f2812a09b4fdc3c246b7379d41d3764ba17fa87c3e9c131095864cbb5f54771a204 SHA512 c190fa0acf7ff15fa67fe172911cfae803b2a8c08168570a5518a40767d08134f147259a413ab25c45cac5dbf2f601a9753c77ab0eb2c180cad2fe48cfe3867d +DIST futures-timer-3.0.3.crate 19739 BLAKE2B b7af71c761197056a6a4db03caa30f31c104de0049c09f52b18b80718ad20c95e0e64bc7a3618c29d1c9a5ef0309379044fdd9c1fee8465930d28b2c58927733 SHA512 c50388e38b45dce2a65a8d7ce56bcd9c3544ae677158c4c10c532136e861c16f0f52df5222a14c0f40ad8e4faf93fde8223affa7fd84d24e95aa6994177e7e76 +DIST futures-util-0.3.30.crate 159977 BLAKE2B 9012edf76336952dab02cb61db48dfc74b6cfc17c137c36372709e8d575b306a4d7c4da89328067c9482a645aceb7b44ef57deb21a0c25964a5515e738a039d0 SHA512 7faae5aa35641d858d0f5430e4a69acd4ba9037852ad73c5a890bffeed411d28820883e18bad4ca8f7b0a765f9f4c5dbeaf5d0cfaaf90c2c69846434ae091951 +DIST generic-array-0.14.7.crate 15950 BLAKE2B e74c785e3127095625951da192a018281ea9976aaeb11019f9088c3f27748c5fed1ef25d577150864486dc48b5138d6892e42f99979339f711a66fc70756c82b SHA512 363a7b04e4102f9ca63d429721c1ada6272be6bf0a2e97da681faf76381f73f0e3acb86623b9ce2dae441de9fda704088391779b9769ec02b3c8c9f9f35f897d +DIST getrandom-0.2.10.crate 34955 BLAKE2B 8e7b8554ae360484ceca2a05f834c2664b08f41cbc6c955663e1f8f22fb5750481518bf1c7b49f49223a99a66914ef013347b9186acc97a20249f3222a13f9d4 SHA512 82af9e0417bff9272ed0478be4ac90426405ce210014b21899c6b95fde1b16893bf46295388ff5f13fa712a04c99c46b770fab83f41a1343af1590a86ca8da3b +DIST getrandom-0.2.12.crate 36163 BLAKE2B 0afef8504932ea0ea051cde1d14bd5b79edde68d6ebae6fe88fa4aaa532605a16f466d0d9c0d0aa619eaa105600b6d5ee4e191865a3fa041549a78f78ca82396 SHA512 dd97d7dae1a7ba653abdaf2db719e1a9c8eb721b08b4af0f1c45b1ed5079069d1b57e4f6d9d879e7fae3a890763f4b6aea9bc2d945392b98e811e7b348589bee +DIST getrandom-0.2.15.crate 37163 BLAKE2B 7d534e799a4711d01c6553b8c9422dbf01e384a850fb0f7cd76e444628f2b96d28d0f5e8dae042f8081a2bf9340f57c558be50a6f22ed5fa6b0301a15898fb35 SHA512 04789a53d3f4a84862e1e8b2113641af67e471b468de1222470d5e6cef0015232463a2cf3c3518dc2a533b3983b175a7c8922da00665bcf71c1e4e279b67e6fb +DIST glob-0.3.1.crate 18880 BLAKE2B dc89b3a664e810264dd7a01ad892e865ce35b504bfe5dba12d7ea8084da7de84feaa94c2208f1a1eefed90297e552636ad61ccebf6fc8cb4d01f27d605ad0a09 SHA512 29368160138bcb7ea5660f9f30c5711cfca8bc8ba836bbade3fbe8c424e7b4118daf27cffa677962e37e36f025fd2bb5a9c2aea865b0ff155cace455dfbb658b +DIST globset-0.4.14.crate 25090 BLAKE2B 2c3e6f8384a066ebfa1f36bf03125b5eae79329255674e32c58963451d4b342ada10f17524232a953bee133b3c77b678a141543759ebc622b5fd659fe55622ae SHA512 e83e4f5e42a97609e2579b09f49c2cb0a76a94e7e2975c5871f2c5af5d3b809736e0a7b220404c582f4a0c7eebdbfad6cb432e89b26401b58f2b253f8c0151bc +DIST globset-0.4.15.crate 25177 BLAKE2B 5556f4cd7c311b2ead3a83fb2c84280a48e493f024bfd7269c91cde6ab81315d2d7f051f7cee9d7d34e6c8563c2452f0ec04a9d5a8ba5273bce66f5ff8f9054b SHA512 b9281b8bf48d2e297be533aa31c701c0115978b4e580b684b78a385eb2ecb4125187605368a6858311d6cdf5caae7d733cf1406c79241b7d19e7193f5a111dad +DIST goblin-0.8.0.crate 175002 BLAKE2B b8a1af5825d2f9b636c8c5cd120ddad860b7bbe6573c8ee71c48c58d1f563c34a0ce6ae7749bdc0a8ee42c00fd9531fec77cbe9f6565f03c3caa9b3498995c1b SHA512 e6334edbe8589b8ef11012588bd4c28db756aa591c3523d2868c20843211622afdee9cfb1f953212ee8b6563a6fd2f330f026f74b7a20486bd297cc2c25f6de8 +DIST goblin-0.8.2.crate 187412 BLAKE2B 1512c29c78cb53b9ea84cb007f37c983c2a20e33849b118d0f22d82e87efe37ae3c24de284bf3c4402a37debb58443dfcbbd335cbf8176f5c7f5c937926f6af6 SHA512 7c193740543754bbfb833232882cb9170328144bca684a442154127903f76e87558d0b6adc0ad9546505160567ac311d716a754b02728297f9624bdd9dbefb23 +DIST hashbrown-0.12.3.crate 102968 BLAKE2B 492072f27eaec45abd2c5d7405c614c0c6a8221425e901bb6174bfa1688ee524408a618650126d6c683b7285b9bf0a21dcdbff7347e4d8f97bf7111defa1b7e5 SHA512 b3700fcd659a21a6b9b3777c18b37a83bf25542b4e8f2b963779a122f5d22e1742c064cfc03e649583e7dd5c6e90ca8407f8c51a0e8755f6a108682853022f76 +DIST hashbrown-0.14.3.crate 141425 BLAKE2B 23c63a99c6c6b7a6b9b9e8bbbc7f1e342e1eb9d7582fc9eb408d3eec50c99f34502d450170bcfef4da7f2b1e743e1d1619875ec879e4753dffcb84f3c10dc3b2 SHA512 4d344e5c89ce58e04668b80ef10e4e110a3a5daf4d610c52d980577795d0e2050c7d0b151d8ba97128117665e27b92ab0300f85b88bd6e1de943c62d49249356 +DIST hashbrown-0.14.5.crate 141498 BLAKE2B 7d7f31b6377c901de12f78f0004a347e3e3b948b1336a54b6abd8dd2210db0ac415efcdded421a00723f16563a7b833b5d1db3cad5c12cac916e273bf3e588b3 SHA512 215ea860bd3de80e2dd2d4647c9dd31c0ac895ea7c08b87256dc11d36407e412ffefaebc6cdbec024057dd4f24b3762b4fe427be307e15d1e68ccfde89a99742 +DIST heck-0.4.1.crate 11567 BLAKE2B 520aeea740cfa30b0cca12f73594ffa655f32959673b1c9caaca1ea0162e455546ae3033881394c0ba0516bcd5c9a997da02162e1585522d665813b9096eabd9 SHA512 8c80e959d2f10a2893f9a71994720f90747742bb5b61fc0a539eed3ea5679b140c48fd7f7690d7122cd6af5f7f20a19d412e3569fe741c6d31f6b2ce1e0b80e8 +DIST heck-0.5.0.crate 11517 BLAKE2B 5365ec43b2239a76b33a174f1a4292ece4147f9d382a68c6c60db78fdc8bad0afb1d51a65bcb25e96675372faa4ea37c318265030b0546ba51942f7c929e1835 SHA512 f044fc9c3d22466629fd8f772ec0555350fd611c0cfadca51d99a3d2f10e155f77c1091916c8a95a6b9b499f366c2e99a5fbf45b010f988bfb9b2501bf9f6a76 +DIST hermit-abi-0.3.2.crate 13783 BLAKE2B 43089507a5ca0731a9e9a54fdc8f4dd5f807244797eba5bdcc072c2c2b3761481df65b8cc65900769777d9d21f8345b502cb1915ec36747160e87f179469a661 SHA512 22901ec8976a7c96e93c9e07a2c5d3db49d7af60ce60c7ee6f61c3cbe93190d1f285e737c1c8b2236d540ab14e5d92e42828ec05f1b212332a862baf2b1b57f6 +DIST home-0.5.9.crate 8760 BLAKE2B 02277a6d0e54a88e62a50ceb5b50b08cd5dc1ca5ddc17a799db0f49a17fee8560df53f616ae22cd16020ae2a89ce7c6ec22e5e2c0d513405bc2859a6e3ec61f9 SHA512 3f1f7b619f1a47694cda92321a11d66ebbb2dc0b0c33446a7a4b886f547ee88231b61c038de04bb82acd50e617f19b5085893b8401206d32cd54502033e04bf1 +DIST humantime-2.1.0.crate 16749 BLAKE2B e2ae8325b037fb175b9200cc5c1944ce579056c6662cce307beb6701894552362a25e371aad65f8fb9384945b48815ca74bb8b544a32e0a5845b7edd30b918c9 SHA512 3bf29ddd1391d82897c22baa0ff3ed58ef6d6959859f1f8ed54d324caba5b6fb4422e56790511ce82f902cd11467f93c8ab7fc7b0e0bdb719308a4d0a446ae0c +DIST humantime-serde-1.1.1.crate 7886 BLAKE2B 4c66a483276e0cc5f4bd82fd49cfa0ee40c8ceda753919cfb7a8c794d098e9e4e851643fbc42a209d6ab00c5c62d9edc81c3bb1f6da218a09eafc96da9b566f6 SHA512 0bd72554e700f89506d2d1c8191832aed0065ea02aacb99e27139a60c883d3dbabb1fc3d60f499f5aeb20bd155fdcf21dc671aec1ca68d4041bf98ddf324248d +DIST idna-0.5.0.crate 271940 BLAKE2B 0b781c2e9bf717af429efb53bdfd18244f2b8c58e5111c3bd3bee50c8a01cc747513fe20db75c38b6b771d5845647bf6c1849ae6667766c9623e018c1f399a9b SHA512 bee6cfbfc99859b113aa8c7b487429a836dabc4e317980f132d28ff8333336f33480bf9f8b186a07115eff33024cd855bc85d346fce85e17c4132e886769c54c +DIST ignore-0.4.22.crate 55462 BLAKE2B a9a29e5286c9a9c132f2fa319226bfa85c9555150afd18e34bd3b37915250842c46f6079208dce75674fef448450dfd23242858ee2e4e2bdb7eb65f89d689d0c SHA512 9647a4887258dd970c87798dee32a16c1cda75ce3e352829f78d97e1b786d67f74d89b2fd76d48a607fe795213965c04c9dfb47713f8fa80561f87ac465956d9 +DIST ignore-0.4.23.crate 55901 BLAKE2B 8c5138e723cbccffe84aa215b2e73daa18d8b2d39136a901ba1514def3a67437f79d932e4762578dd1b28dd8360a397aaba29ab8bb67a93a587a1c71cf5d1aa1 SHA512 ae354b00994ae8570751bc5c09167edd0e2891709d4c4878cf75b24619421d23a1b83e28886d54ed9d31aa427f49153e9a5fc42b5de7262abda20c1c0061b299 +DIST indexmap-1.9.3.crate 54653 BLAKE2B 7bc1768589e74020dc15d3dd064009edaaef39b7aeb682d0ca8e49944e3f020b9c04d64feb102e88b22feb40863479dfaf4722d6a77b5d19e7ca553f4bf64c1b SHA512 2aa8069eb07a814c8fa3e11296c9f032ef60963520d7786ad20cca5cb7e73b8f76d97722a994d65295bb713020aadce5008cd3df5e99d8bd968ef1979f910a37 +DIST indexmap-2.2.3.crate 79019 BLAKE2B cc87bac104efd9aa565e3b8d6071f271b33501e2192b3a478120c41d015537e807bf3ae808ddab930aeb861f353022ac76522e5102e32f72722b93d36d5f2236 SHA512 ddc45ebcfb36d761d8c11b8f61bcef046a51eea71692d89495c897cf9b4cdb5e14287600285297c8a6aab543761d9f5ba3ab45442803837a810b945aa346d48a +DIST indexmap-2.2.6.crate 82420 BLAKE2B fac5cf6339dc3c0a40b100035a5c874cc7b2efeafeb31c51488d25156e392dc9db86a497e76eead351d2126f69d060422faa9c55d73407a0de9f5be18d234123 SHA512 53211c4a9003d751feb6dcdf1a76495764cbf32d24bbfe2be7023946622ef4f2b07a6de57109e5d24ee01892f4b2be0e0692e10cd31fd39c4ffdff4d37abe9ea +DIST indexmap-2.5.0.crate 85919 BLAKE2B 766da0a2ddc406e3fb1a70a0bee00141045ff72b52cc412adf05972ccef59d416f502c429dada111461cb522a5c442087e01d8fb235c2f1fd5493adea00e79dc SHA512 c4627d43b1bc5c5fd64861d1a7ed66255ec3f790367028b2758a40751286d6677da7170cfb04dd88ca4c2d163df621583d2e0dc4e9db6d7ed9bd0cbea42b1729 +DIST indicatif-0.17.7.crate 63108 BLAKE2B 665bc2077207cac6ca2071d9e6ead76abb30d5f7c209d7b4a2ff5a1fcba566b331467239bd9168082839c961acf5a0522ae4c899aec141ccc649025b2eeeacc3 SHA512 412955eec523e961a20bb48f9921128004e723b405c8f1bb73abfaeb4f532ac6f883794fe6c8738a40c2e0a400a6ebf94ee17d89f7cdc98d9d0f8611d84a369e +DIST indicatif-0.17.8.crate 64869 BLAKE2B c534020b2c7b25bb07cdd0fd4414fc817506647cf5b8e2081c22be58857d5adb170082a3756004c69187619fc5625f8b9a1904566dc51c621838e09ecda5b43e SHA512 487e73445c5c7d3c16d6f93a3d9767f41b37d2832e56851154f8b69e678ab7d9ab04eba225a6bcf8b48842ae0db0249b060e998e29a252dedf8afacdc88b1aaf +DIST indoc-2.0.4.crate 14311 BLAKE2B 8d604e20825ae64530014081c627abe4ecec6447e1e214408743aca79ed217531baad4bd7021137ae6628555d769a248f06acc556cc3254d2626074aab110a44 SHA512 ef1b8d19d89d848c1133f2865247e0ce23cbe5552454805910ed0478ac4acb11b11629aa4a5ce8756d0ed5cbc0644abedeac0246f433166c68f47cf58cf4487a +DIST indoc-2.0.5.crate 14396 BLAKE2B fe838c6a855d6ff7396675a3fe9b2e0b06a93cfd4013b0b843d24d2fb81f6566528bfd1753c649646f06cb7e59262bd6ec3ed79d4e6f01d740cf0682355f2e5a SHA512 095fb56a3d87946c42a63065a8b276c2d4b9b835800014b400bb987593bf56701bad9f55d947f090740fdb7641a4f3c87fe8bfa5724709e95254d1e8e2e3616f +DIST instant-0.1.12.crate 6128 BLAKE2B 728923f757c1ee4e4a7afb90e460eed81392068961240a538e5c6468e15a0b6491f590fb5f6cc46e6d78901ca232351f65abb9f2f230d8f4983c5e58c4011902 SHA512 fae494c00111c51c840f9dd6a10febe403e27ebb933dd16633a213e9c20f2bc11adeb431c71f8a6713bf88f270a010941e15d83df294e658791934f83a5d2407 +DIST instant-0.1.13.crate 6305 BLAKE2B 83a2c479e21e789ca9795f66116ebc55481a42afb21f4c0ec0551edf07781901a28978667e92b01355b43e0e1a7ffcd3cc37b5501a7521da78f4f352e586c9fd SHA512 b7839431e8920c4c0841d0974eede75fc50f2bb7a9475664bd2c4ff6c558a10084e1c025e5be977c3364ae9112c365c0a6f480cb9b35ee4130ca2beebcf650a9 +DIST is-terminal-0.4.9.crate 8109 BLAKE2B 0fa495da123f6fe5e3ba5f643f1ee097fc4f8e8aa54d9525b6108855a6a2e58556534a5e8dbfe7b5f8e2f1932003ac63f6aa3384317de7b385cf724bee294468 SHA512 0803ea53945715333d9b5fb18feec7230a49cb1a5f7308e2ea8d06a650e376794dd372be111e85622fd21320228706dd589423510dd010cd6ea112f185c46966 +DIST is_terminal_polyfill-1.70.0.crate 7451 BLAKE2B 9efe76f14d61a5af6d3cd30d5e64209971d4292d8d2c12f4a621ef65324a5bccbb7e1d79d5efa75ea7456431241d6325cdeaa0af802b1480c6cd9c1bc5a35994 SHA512 c07d5076978e4c5d8d6a191d8880fb62643161979c473564881feb17726cd9ac8da25c40094ff12727dbdb064fe88fbda1867120a2c3fda1051bcc39380645d6 +DIST is_terminal_polyfill-1.70.1.crate 7492 BLAKE2B fa663f858ab8e5fd56202d731b572bfdd4ab0e8262100424e27360a9ffd2820182bc57d6718a305ef82d04c3798111841c0d9f9dcfe219765c0f63edb560dc1e SHA512 4730fa09401cb4e69c92b38b2b43afd74699c61f5bd7b37605efbc0c08ca7a1318d43e4a844e46e0f84f83f42432f01e33771be2b18eb5977702ab9f894837e1 +DIST itertools-0.11.0.crate 125074 BLAKE2B 8e686f176764e92e4da3697eb781e1bc30d6c57ac61d97343b4fc3a48e4febf669d5771fa8620005c620cce52c236760ee2e1bc344cf602e878bc168a2e69cab SHA512 8ece00ba0a7cf481ad4586da24385a6f0b1719b9c3f0c25b9b5b373dd1a0ca7b9687a77cd179853392890b7bf4d31e0356a4e5fd540465b4ac62bd74ef717fd8 +DIST itertools-0.12.1.crate 137761 BLAKE2B d7db67feb7418d6a779dc17d8a2f33481114cd81a4d53a10cffe08e13f0d3cf4525a5ef43368fe979d5a3ce230872eaf993f7065885531aeb5a6479351857708 SHA512 0d9c1849dcc0ddf7555b0aeb7e4f2ef3b101cfc6f03310ce1b6072d70ac8c8d3387ef4c726146102012e75171e0b0bf13465704b6edfc02752e349dc6af7cf68 +DIST itoa-1.0.10.crate 10534 BLAKE2B 8ffcb345d07070cc01651fd44c19f3e0659185eda733c407fd4be0955a301879ae1272dae7f425279dae8dcb7f7dc954465c9a09b5c521938a503d34fecfe2a7 SHA512 fc496be0873e31afa6ddf7f2958030f8fcb517cadb86a48280a0c50ce50460afda189af1e6c26e5ff6f85c750d772c21503864c32b526c4fe4bcdb5b07918538 +DIST itoa-1.0.11.crate 10563 BLAKE2B 94da07e0f7f2535d0b1491b3a3c64905274b315ffd35ec8e9a3e36e26cd7211733b462eefb5208963e388345f65be9694804c344a6132b2b595b0bc716c0b328 SHA512 7e22dffac34c9c9f432daef395e0ec710ed658164bc9cd9fc6445c9f984c912a10bac556214a026bcddbe27a3197b35b0c87d6709fd605062637d086b2d20311 +DIST itoa-1.0.9.crate 10492 BLAKE2B 0d5acef9ae72d3f4b5a387d231952e6025def69da81d38269b4882bc534be7acadc073e526fd8bebdca898a98b2c741735c541e0b6a35ed0f8f8799b906b65b1 SHA512 95f7906edb7d6a2690389167f8c4d01bc37827205bca87d527f2eb33722419ed2f2e8afaa559cc5a0a7e7fac76515c9c44c71c42b536aa34b0e2858c40946b6d +DIST keyring-2.3.2.crate 54145 BLAKE2B 2d09d1bdca6b6fc32a38c178f6b6bde339a699b882beb0f0a9feefe639112d67884dac941f9a5ad1a17bb4faf348e24313282900b49dc1f2e9a3b76545da7468 SHA512 04eaed986372acf559e67453b506e27d86092e9d0be963d24074d1196fc34bc2fad89cbc8d1f227052398099a48db5b789e2c0c7ecc8d19dab000bd02fcd3b7e +DIST keyring-2.3.3.crate 54379 BLAKE2B d6fca88aba978df803487651d66e909119eb784ea5078118c4cdbe29798c76578c801dab1f53a5630c6cc7e8ad8f360d301074bbb95f491e197987ad6f729898 SHA512 258e795e8f140546ea2bafa6d67438aceddcd947a289aa2df03257aaa501a569e5643a0ca9b0b59ad180b1c5c6e54b96c9309a1ad0ead2dcbaea67a94491ba11 +DIST lazy_static-1.4.0.crate 10443 BLAKE2B 25b2e61bbac48f0dcbc79c81d7bf01f2403d8269ecb6be3ea6147bd00f7a588df15a91f44dfc18ada19b21faa71de4637c7d493a8628cbecd0e547d74e616a23 SHA512 e124c0521ec7c950f3c4a066821918da7a9c6e711115d98009ae7c351928fdddead852e7596fea5937a9c30e4e4ce8eee7099b20248b5d6e3b2494b6a6d88cb8 +DIST lddtree-0.3.4.crate 11469 BLAKE2B a4b152d28962380e5e0c4ad6e1e590156ef21144e6c9c8950918ad66ac5451f952e0d575f60b9c898e8c0a3c51efe1245a0f3f097f3f42606ba5f2268c9de10c SHA512 d4b4fa8acfdfa8fc344f89d29937a520be3673a27888edbeea68d1deae1f190ca7642de66784f3109b8a6bf94a1665a39a8025dabca63d401aceb4e1c92fda7a +DIST lddtree-0.3.5.crate 11488 BLAKE2B ead51314d115bf047e11be4639de3a1927d88cf1b0d46301455247d039a1ce174c030eb00cc2c975930d8a33c7cb5cbac1d200d2250bf20b7a59b21d0225fecb SHA512 42798dee58f29b2192677d716c864102d24dfd896ca62e30fe86fdb2bf439d8ddc9f8308d4e4b71d42833c070c1e6f0705c1b10d002520f294fc68f57b2c7748 +DIST libc-0.2.134.crate 603330 BLAKE2B afca337bf7120e933c56745a51261156f4af7cc58427f623b9cdf1b2d5fc67fb2bc7c078ccab3cf232024e5013e8edcbbb0baab6a8a3762f9b20d975ed92411d SHA512 fcc142061df7b363b2dacec5fb3c9a19e63addd8210678117f681b8e1b62e5784cb78067639df464f32e22c9ab4d0932bbe1c01cc992348cc0fad4a46cc7b1c3 +DIST libc-0.2.147.crate 686772 BLAKE2B ab2f0c65d071d46b8b88149add1c8429237ef6d9e0563d56ee1adbf23e6147dbb57fb68fbd02498f8ec75327693237a47e5e5259615ce8b0d5ed7a03bbf4fffb SHA512 bfb3c230b59d623b98726f92b7c3f897b47ba3d22fe9834c15f5b4c1b662289aba35a0ae3acfc704ad74696db8c691ee007b9cc6fa03ae65a18eb6bedc81931e +DIST libc-0.2.149.crate 715592 BLAKE2B 21dd5d4f9351f3c75790077c7b025046db665f2d48d7a72cda7667bc60febf79d82708cf7d39a323a594397cd590bd3d2a2f85349b4473b90ea4da918382ed0a SHA512 0def64d400d473d6eed30e985522d36801ee6472b15f90e74dc4592e0a8ffbaf30b731be280de52b30255cf60aeca8efe817b67049227dc7000c807e007d7289 +DIST libc-0.2.153.crate 740614 BLAKE2B 523a41bc8cff4ebcba0edbbe9e6a2286ec7cb3ba5e90ca5926c972b68e4b34188bc077d20c22376238c3cd91b7455898a95c505ace4ededea88cc496edb4c5a7 SHA512 3f99e3a192974fffdc053ef21e9ad5fb54b7cdbd4755df176704a95dba38047138ccab76763e89c6b565f37f98fd549fe368749f84f6d1638b3209cb07eae9b4 +DIST libc-0.2.155.crate 743539 BLAKE2B 42cdcf8d4a187383548b1f09d404474f168916d626d614463fe10a1fd886e972e1caf6297e75445214af3f31fe631d0927e54ec1cdc63e20082b3587e38dce16 SHA512 05354bba532b8338bda1f88f12c7f3893429734a06e33925fca2b99d49548ae5216e2cd84e782d2368a2dfef20b0e035e2dcad8dd13ede7119462a8c639b2807 +DIST libc-0.2.158.crate 751340 BLAKE2B a67318ab24bb86c4df682cdf846d51f5f0a69504567acff43cc6e724f2641521945dc75dddc10c1c265fda960cb28b528575b5d39ce321073844dbddbc77bdb8 SHA512 c2d90d58480cca3464db475d7c70cd66bc1492239d8183038b48def8f5d8a437a1e2a2f084cb2bd9456889221b10aa07981cd5e9bcbb6bea28a2bde3c76f1105 +DIST libmimalloc-sys-0.1.38.crate 196009 BLAKE2B 355f07b19a5fcc54ca95cc449a9c8200abf11984e004d3ed405f0370f29a18b878e9d8fde63c9bf84d5227388905d288ebf1ba2df38d7c5be8b0d3e67b63f55c SHA512 3b0416b06a4692be364b75e324a312e0160f64f8a49930d3e0eb6fb201982b59482f636fca774a254aead6112168acd3d307c2a79c5ce3be3213850c172a7bf9 +DIST libredox-0.0.1.crate 4212 BLAKE2B fecbb90e2842a69f3967bb2a09b0181dce1720b60c5d762a334a279b52c00a9b4b52de72c6484603981c0c3e1cd8e173ef5e15fa290ce8b8888739204956be92 SHA512 31a9234201f5128f1519e108f7424d1740a67699828265cc725304a70f6a51e139f1d0c0e626b487857a7b421f25ad93e81b95b65cf0d3e0ad912388deecfb41 +DIST libredox-0.1.3.crate 6068 BLAKE2B cf09f261d3a945d290ecaaa724903e0042d66eca46dde8a40c261ccb1e82c0d6b9926898eadafc6313fdb9f19cde56377b8a9179935482559c4b9707e327511a SHA512 c62142fdca92388664eef83fc89b8607e2df318cbadff6edf9e3d927837853d5cfeb54445299a82054a0ca81853b0a33536966ab26f1f2e0fa43b39aaaf67c49 +DIST linux-keyutils-0.2.4.crate 17999 BLAKE2B 8885c1e5daabce113d0e68f526d0f323603f8aa6bebd1ce37e3f64dc553239c1d8d0fa5a662190b901c42cb2ab061962697654b6abb0530333f23655911069e5 SHA512 8bcf2d3eb2c5cf49ce00b91bff578e2dac3c9390ae7b4bb0ad3ceaec9d282a1d4782cb9e642cba75429e7982e6537a72f849a1cc848a939d6e85fd6ea8e1dcb4 +DIST linux-raw-sys-0.4.10.crate 1407767 BLAKE2B 8bc633d99bc1ee1a6fdfa19501fd034a4475fa9ebe18a206e4254309d91aee7a91fc70faf9775efa5157a1b2fb7e5f827bde40a770b066643356113f2cf38b5d SHA512 107f61add087bff55869798d5c71bc6ac9ecb27a603d8f9071b856189de8b7b0a7f9243fa1433700f52a0c3020eff5604dbf6e0653109d0dd277b98ab45fae21 +DIST linux-raw-sys-0.4.13.crate 1493855 BLAKE2B 1298a038276e2424eda9873c642fb43d864b343b03b7962446122d2dbea94d58d9fb2b93e890769e6fe4092378755413ed6afba81ce56fd61e512146e44148a3 SHA512 3918da6b667a08ef8a51aa0b087129e2dc5ab101669cbba7690fc98ae2659a36861bf9410a3b87d18522a7549d43ac169b995ea192d3073f7249305a809cac62 +DIST linux-raw-sys-0.4.14.crate 1826665 BLAKE2B 804af73daf396bb20da14f831f26ce06325181de14f0c277350bd22d21789f2bdd663a964cc0e7c5cbd2e084285d02a401a6bfbb3e8a8f079c120f9488b56f99 SHA512 28149660bd975ede05624af3582d5c78f498239f5d89713c2c32f5372fc16f4ca024dec35f81ea973a2cf986098890395dbda06ac6cf4ee29df3f9a0e11eaea7 +DIST lock_api-0.4.10.crate 26713 BLAKE2B 113adf8554c65e9782e8fd0360d0398567dfbfddb1fea4928cc152fbab98dbe086e42b81170f6f5c333d61dd3261e8a1ebfbaed786e6bf6378e6afde6d7f9e5c SHA512 ffe8cad8099bc382832181c1ff95e0935993491f247114604201be7d4ddf8402fd4db8fd6499c611f95fbce7d57dc3d3738eddfab31c52f50ab8709e549697db +DIST lock_api-0.4.11.crate 27487 BLAKE2B 87116cf908f7f1f9c300cedded989df305f855883e3df5a482de2c76814c48739582d3079d76a2bdd14a6999204b7fd31dcd8fd06d1dc7f9418f0e2f70a1450e SHA512 9946adf313a5c67a0dd87a1b679b7d9d16a86149fb95974d3f28aa57a9a1a3932e4a5ee1d332097559329c5e3b2295be2e4b655b115d9f75269f33a758b17fb3 +DIST lock_api-0.4.12.crate 27591 BLAKE2B 4504d146a114d8f8e1fe9ae70b993c713cbfe884dd69c61c54dec978733b95a853c3e5af26f237e48ebb4ee9dbebfce0f6c06067f74a3d122e92f5ace40e22d7 SHA512 525d971f495449bbd02eb70fcd84d4aab05ca582142144a5f314f9aa67ad4c5b4c98dc919a416d0ed2e555063eab037a441d671d56b633f2cb75dfab5d99bcf7 +DIST lock_api-0.4.9.crate 25685 BLAKE2B 8adf5c3cccebdf6aff6ec977f230cd2a208b0b188ef57deacbbc6019431f0ede1a760b2384ba3cb49c96b8a589dc56c0f46a6359b3e62277e7ae1a1c3f586fa3 SHA512 9215381d9bb6b80d217c73a900db43df043b3e939b5bd7a292a02e9ab911cf0eacd8f883d35bdf72b3a0e78df8f1bc3e843ca4c775294c7a7a03091dc1a74990 +DIST log-0.4.19.crate 38073 BLAKE2B bbc8ce51ad4a01562ecd204a531ec7d82101a342ec26405dfadd1761372f7039297dc97f4899889ebdf4eccbd56345e015d4ec6d2788851e523db56eb541aab3 SHA512 8f11ca6f5a99b61a5f3baeb7a23b7a879b3a5bed666337936bd1d8794864d14a6c4f0747d03505831783f15d8c14ebcf507267915481dfb1b32188b8ab36a038 +DIST log-0.4.20.crate 38307 BLAKE2B cb9c9a401b49bd68c18d5e42f2ed94446f1aeb184caa23cefacad4ce54a2a357143af54a5595c45d6f3c3d20b054c451d9e6ccdc09c19cca99ffffdaf8bbfc72 SHA512 8661b0c71d3b7fc0d679aa3d7f06910e6d3da1c53862aa06526000e1bcaa0b0b068415a1a9ab317c318f00d15346dba8a4f5d2a60d8850790bed9cfaaf757b3e +DIST log-0.4.21.crate 43442 BLAKE2B 8429b3270794d3e2c7f7d5b58bd4fa1abb9d4807ab3a1ac980ac81c11d9544635003d8cf2e608c2c0094865459108a2879f280278e121df68d09bc1561d604ba SHA512 0becc1a06b6e7048cff6c0bb8df49a16ac4772133c00239e9e9459c0811e7715c500f440cf1a9aef8d7ad74f57434559ca9b55917f588b8e476cf36eb6d4e10b +DIST log-0.4.22.crate 44027 BLAKE2B 831dc5092db05123bf2e909eafa708339983edece9bc8cb802f0ab418d47ddc5045a72c1b58bc7c46ffa68080eebd0fd55d6e4f5b3d5ad3b0bc6b2ea0dcaace1 SHA512 bd7baa9c8a5523fd0864a53bcde955d484cacd782412b5b02c890b89dbf62137624da3a27337a310dd8f62bcc6606925a42bbd4ca161a3b7936ea4ff96bc0d71 +DIST lzxd-0.1.4.crate 21891 BLAKE2B 8271b79bdf6c65a17b5fe77a4d8b7d3a96ccf1752d211770dcccbd0912b0113740f5175b6d587ef5f5768b7ecd073488fca4f49e5c4bb3ec4cc9e5055e471b99 SHA512 f4fc473056dc793ee938943646416c3a93c748104093b8932c0a603a5f25820b49632f703ea4bc248b8bd612ef51dce4f5798f1f46782466c38aa69d016c2c57 +DIST lzxd-0.2.5.crate 22728 BLAKE2B 5822d0d453def5b937e7414e055b637e6aa018a4ced08c10e88566c951552e5f8b01b1a08f25dd585b9d1eed4c34885f4eeec37c8b9e2472bb83ceb428cb3ffe SHA512 0a558d347f1101e82c861f3f6b8d3976ca57a4dc577e328b916ddfa4949e5a4695c89693f191c8a6664c15d4da8caee10d44ab0a79974cb2eb5e4e73785e17a2 +DIST mailparse-0.14.1.crate 37264 BLAKE2B 322c5ffbb60be7a62f9169438d0678ffc37fc3055568a97ecd4673e84ca4b49d280cabe773d8dc8dc99f68a86228886bb28c56152f072748a2352dadb0ec4710 SHA512 a5b19a4612d84cbf3d89cc26033484e2ee252d0b5ac063cb6487a55f30e25a21b5108020046926858a65995c48c2dc3e5cc64f705291f1ad9cd74b16b3c6d360 +DIST mailparse-0.15.0.crate 37293 BLAKE2B 3ef9c0f3e65288066a1a792b3ad5bf4ca08126573fd15d9360b2d7748ba623ee0bf3eff1073b3244f1ca5007c2ea9c4e88310dc3809826ae940b13091df47134 SHA512 85899a2a65d195778615e3cebd2e5b6ad2ea3fd2b5a8929caab7fbd3e50306a5c99328deb7ffad9b3135f3fafca4c4e74f372e42a88d2785ade215334b92b416 +DIST matchers-0.1.0.crate 6948 BLAKE2B ec3a5d01d2fedbb4dbf5bb185afbb9401410463a61f51674e0df6a571db352b2bbabfb99cdbdcfb4e511ae783165bf0258f5163f240a229b9087f9edbd0df41a SHA512 84214c1a84952d85631aa1ab5115df7cda223ac64e2acf055b6129ba1aa26ddc87615a8b51ca890ce3fee0419053fa7fe1599ae128f1d211b58c07b0c4af3b19 +DIST maturin-1.6.0.gh.tar.gz 464510 BLAKE2B dc40df2ae593d57dd8d52526734cf6e8cf01c42de4cd92b5ee0d4a20168367bef6b6fe783dd7e2ba51d96b91510699a207ada15c69f97cc832d34eb5f1028ae2 SHA512 de67ce91200fb17ffe40587ae66b9a39db53ba74512354aa632631097926833be01dd685eefcfc95e9f13535c73ba1dcd166b2111d987769aa109f4a7f8e2c09 +DIST maturin-1.7.1.gh.tar.gz 505952 BLAKE2B 0b1294277e3e203a38d904782fb9e9fbc8336f50670abd1c68b8c8c2ff2a7dfdcd8fa6e98dfb4b43c625349d01f6b89826b8c9740e7660629671ad4c07ee0fd7 SHA512 7022cb87d5710807f1b8e4e858d19e2dc2e07b02d7f47e9bc6a322686dce90c7aeb8c2f5caf7b5da4ca61cadbede7daf84728ae9f341c38384231872c9be5cb2 +DIST maturin-1.7.4.gh.tar.gz 511488 BLAKE2B 008b2d67d553479040fcd3062b93ca12dc6f2b98c3d6cb43cac7ff0d8e4772417b99fbf2a73ed96cfcc8a7372b37d845e8485ba0afc80342943a10d716492377 SHA512 72fb43a10d3cdf35eca224232c59723bff5b9230c7d40ff01537e1ba869254b4b6e9a0c52e8b7154f7b74f0f0b5bace4e7bb9ac5257c9fbc04750160791c35e3 +DIST memchr-2.5.0.crate 65812 BLAKE2B 57966413a1f933dcb2d2d4ccb29c247070f65a83299b2a9f5aa83f5a48a5c5f1c4c7c632fa63bd19f9508e9291e7258db2f16e2813a56fd84e0856f70f1e67ab SHA512 444a163b484c233e78c0e2e4d51f01ce2da93d7d29f516a95e4b0866b20bdfd3f34137653abed53eb70387991ee3e2b5937d8d4360a85bbcb50a93005a75defa +DIST memchr-2.7.1.crate 96307 BLAKE2B f1a008fbdbfe84852a8ae1d9d9574306b1bf120dd5087903adbcca6af342c9abbb296496eb9bf6cb58915c4444b3edd6ca4e27131ac7d8aed8849815df87a944 SHA512 5120496faa31fc427c8b4178461a262b3a34d70eddb7ad17a19d6db8b9969c9e113d3625b5e6dc677087fc80907377b00ba0421aba9a92cf73ca2849d932f473 +DIST memchr-2.7.2.crate 96220 BLAKE2B 2399064b6db21838d4aa0b25ed0bf04940ee3820741658cc6bf62e5ade08f41320df743ff13f99b2781da7b844e18deb1cfe25fe570f0e93f98ff03ca5d442e3 SHA512 cadcb4239c7f3aaab042592c5186770a225621e32f8583052fd3dbebb4a6d9b99be28f589b39b5ca36cb2d56fb3709e7d4ba91838ebb882e28e51280c02bbc40 +DIST memchr-2.7.4.crate 96670 BLAKE2B da38114beca670467c3e1fbf4e415af6f22d52e3223715d52e181babb89b872b46511563985bcc16d7ff4e82f812c6e83ad904b0fe2501b14445119dfa8240e6 SHA512 8d0e8b9c30208897d4b1b920f1bdcccd0c2b75d92a06abe4a1b2407938768abb6487d63de56c6a80419798fe69517210643dfaf11f5f5540185f0eccf220adb2 +DIST memoffset-0.9.0.crate 9033 BLAKE2B 19090c1af8b8cf54a2cf7593748aff4d3dc685ec7080aa476139c1721ef71555495e1bc513b1efaddc7e7702f83e0e1c2a8f71ff40009d266539484c9297e0ed SHA512 2f04f9b6fed31e94388c18162ad275897a835df7b9ac827f4df0f4b0ecf71064ef247f7ad11dbc27d7a6d448984a0f29d1c000e3c8d5fa6e121fa9571770ec55 +DIST memoffset-0.9.1.crate 9032 BLAKE2B 0aab55fe084134bb599c52d77c96400db40949b1013e7037747ada4fcec8dc4a124b6f3755f04b36e057eb2fb4a6bd6f07d6eebcf166f8a71405ef434d802fbf SHA512 3a236c0f481e36973b9f805e454c2efe4dd375e6b4ee406b57145136c70d5fbf4e1183d563ebf3b5fbde7363bbf5f08f0d88e507aae5bda4cc75664ecd0e33aa +DIST mimalloc-0.1.42.crate 4079 BLAKE2B 9cedd8487f419cf1132828fa798af8eecb587abfe2419aa063a1a4d3e24bd0b3dc5c379a24dec6f83d63d984e2fbe5742c4b968cbbc422724c4f43a8328f265a SHA512 d9d37dc9bdaf5bbd5b28921c2cf8d7fc3bf704c6fda893310f5ad43710f22f3543264fbca122097c90501cb543db73b282ce67aca9dc7ce774121085b1127f80 +DIST mime-0.3.17.crate 15712 BLAKE2B abb892b75b40657d356b6b53b9a45b2c822a05873453e919f2bbfeed9e5c06104f24db9cef2716f302198020870eaf96b2c62aff55cc11d8ca4f4f614d7c8e17 SHA512 e6d2ca92bb58fc747c1bb65a7f9023e5dbf4b94966003a72e4913bcaaeccdd6752725cdbd5081e0fd69d9e8f364d79664fcbe70061737d5c39e5b3e3a154a0d1 +DIST mime_guess-2.0.4.crate 26399 BLAKE2B 667f9b8009bac2e1d8b835ae8825afaaa2ea6eddd4cebbf18de8f8fcde9318eacaeeb08066bdd611883bef5f8a53fa2506b57dffff543c3a57316e07b525f7f5 SHA512 acfbbfdc5bd725edde43e4915858b8d016e90a5b483664f0bcd5e8d2b0b3684bf0f6020aea147b5bf429f218a7af8080761cea4c5c04b68fa66fd6a676376908 +DIST mime_guess-2.0.5.crate 27166 BLAKE2B a8ec67e16a336e7d07c9aaa55025c24c3d4a62aae25213ce768786d9f292b76930132a880d662cd9a5d63aa899e9d488ab76fa9d99350e9f448ef484705ba4d9 SHA512 433c876e28394282cfbe14bb9543616cd296879f253ed331c15ace8a7d9f3629f5b596c2d5a64823a97ca9b774acc711b65006c46d54d1e9ee0553cbf1f13b7c +DIST minijinja-1.0.12.crate 136933 BLAKE2B 594c614e22eb577405f3621efb7d02000efe4c05bc326c96427d9ca1cde40eaa1c232c71445535393ff0e3f032353e4c85977ca4ae7e98b4be16639bd3641795 SHA512 c6dd27d326a3924c7ab69dc4e5d5a498118d0e33eca059edde407823d9114eeb8e5ed57089c7fca4ab60452a676ab86d02b1fd885e77ceec9ea44be5e8380126 +DIST minijinja-1.0.21.crate 143627 BLAKE2B ca3305532f286480fd859af3f99bfe346c1316869d60c15c4ed3668f02dc33e6fb0f968fdb820ee924a7f51c9bb079c9001c7180ae3767078eab5a5215803604 SHA512 28a3d116412712f59ce1a6491b80b4c99ed76210d5c326e1a47fbeac234d0fee4f69b953985e526e254846e03fd2d85f93bdda3988794085442cbdade005ceef +DIST minimal-lexical-0.2.1.crate 94841 BLAKE2B e6b8919b80d938d0b98d60d4f5f29ce43d77ebfcf8b18bde08909141915c6ef4f0d07a543538d4f3ba8527a9f55926d4a8e83473248469d087e80b274d701d61 SHA512 385fab51884bdcc7b0f2728a219ab164d0dc8efe42160b918f2c09f79ecf853fb12bda006d11e649f097bae1499dcd41ddf2a8784ee7d178cf2c28059e46078c +DIST miniz_oxide-0.7.1.crate 55194 BLAKE2B 56afbe0c0b3eca98105ae2d507493f365353cce29a6b04910ff26bc75899400fdbd067756cbda7b3d86f047fb8f3d737de00043a4a7348a813cc43e45824e33f SHA512 5eb6ffe34a866403273ff0267ff7838aeb50722ca57a03d5a1d842a5f19a3b4af570b133a3b9d64d78eafe49e4b9732b92dd63fd9c6b0ce59b3295daf10f6a3c +DIST miniz_oxide-0.7.3.crate 55774 BLAKE2B 41e11d955b75ffad131104a6cb3e61d7219a932d2dbafe3ab1229fa8b85b6def569a264b76a47324e35d1b9296e74a19585d6ac043469b61fb9b7565b81022bc SHA512 b9e2cc214d6213fb343cacc5f87228487592883fc8f7cf46c9a26b7148691783b2729ef80c0d0e11fbedf6edb1332dd87d88b253f7c2e645fe86ff2ffd47121f +DIST miniz_oxide-0.8.0.crate 56343 BLAKE2B e4abcacab4c8698d0489faca8556faa7bff53d272ea0c80e2e7843dc0f6f9229b7d5b0a17ae210344722a379853e7f14212505ee05da4e60549081cf77717c1b SHA512 044b641ce6d98d1968c1ee0906f91963f9f524d6f3fdf3059708177a759e1d498c63e595d3a3f0f9f3210c45c828b9b70274134ba078b899d7fefc2bbddbeee6 +DIST msi-0.7.0.crate 59110 BLAKE2B c0bb6d59acb79566343baffc4d40852b0a8d668c48f3c8a482065efb02e4836428167242e382ecff93a2763b4b5383023d389226619208910e44facf57536f98 SHA512 fd206129952baf8d16611d9e376089fc03f5832f237a8ffb7cb784179f226303fa464cd06034d4457bb52b49c9618fb44875c1c1f94ffd42b4d06ab44aeefec8 +DIST multipart-0.18.0.crate 62797 BLAKE2B 438abdd6041c3a52e836b7627bb0a490494b6a0c4ab47d27905480fcdde27e7c18497ef4cae550c14b8c4c34e661176ee640806cc427e3b2e570c38be31d868e SHA512 a34036e1c05c241f130ed30eb7a2d96c2590ea8c0cb7e6cf98c160ca0fc6e0f1227192b45d8166abd7221633c36c57718fdb0ccfa8ff4254d4eeb3abb5210704 +DIST native-tls-0.2.11.crate 29008 BLAKE2B 594511c364e639e309f32f37ae20ecfc5ddeeb39c3f7180c5f3f2cf304d8c323b977af933ffe70cce696a5a63e17c5fa7ddb119d46fc3db819a28e31a388640b SHA512 7e77959932f2859757f1aeb37b78fdd459b7b6fd02424f4b7399525b94c21d1f499a718775503b8f3dfe3b4b740e1cfbee77052a2ebd0994468addb3fa665e6c +DIST native-tls-0.2.12.crate 29517 BLAKE2B 76f4bb2aa8fefc306a04ff50a62d6617f71c3c34aa83ed35f11714ef2306fd82f76c7e26ab7ce50f8eabed40602ba02589dde2d98b55ea6113b45cc539c84bb6 SHA512 15fbc9d02134d3d55334d2f02fe4f64be50db991d75720b38d802088f06cf5f844cba6b25dfd7beb92f2cd367ba477ec2098e3c7336c4e5a5a7fd39c753fc723 +DIST nom-7.1.3.crate 117570 BLAKE2B 5643b67990b7305e101b16b8cd27c447e162a7adc6d0dfac00920b0cb50fea98c9d4edca63c34f6845cba05f8d0acb407cf3045cf64a4cb28e53c8b6bc9090cf SHA512 1ffce08dde299bc0e0367ad59c7b6a83e23decfa11115ee076ab91ec53cdd9ef37e4c2103c96eff23a7b6b8b5c3f67c83ce1917928c7d4c6462083bdfa0c9cad +DIST normalize-line-endings-0.3.0.crate 5737 BLAKE2B 935b2d20ccd37ca7469641a37aa0ae9b6872715d6ee88d568d0ee16fb76416cb1a0c585cff861825de8cef11d864b1dc1b350911c28d64e071d8fb444bbdf740 SHA512 f8e2a6e333b0e8972febe8b9cf058c8d899c384fd177e0b6ef1c5f94e0fa18192963970cb1a2ba80e3135a8cca66cdae6796e4d84ac6b325bb369575bdfc6eea +DIST normpath-1.1.1.crate 19786 BLAKE2B 39c955c41283051e414f8576fdaa51f11f0ab5a23bfb7f6aaaac38fd9474912721c546810c02da335a9095fdd6d8e37ff2f5fad2aa93d93c21b4be76267088fa SHA512 05f1f498f571c57c2307d201d5fa15c72fd2f297b7854757107bb27684470d43a4d40137d31c735018dd2ba50c11f23dfd5e989909e809bdedcd7bbf018385ca +DIST normpath-1.2.0.crate 20107 BLAKE2B 08a86e545ed8d0f1881645690c45c4a5fff438680a36778d938bda03e489706a1086e91e27429a414b5925b15be93a80d8dd2327cae28bd567a058cbec5b6c3c SHA512 a8e20301909e28d6b46ff388ac77c7b093c3654418f74955aaa185489fb859b79fa75b7cc303c0f6ef93b01efe18fa70628b1e85c123e143cbaee98eeb558e15 +DIST nu-ansi-term-0.46.0.crate 24311 BLAKE2B d2e678e0eab5ad48534e686b1a4af344996d1b07a0fa40839072df3061bd7e5bc9341363403ea3ef8d19c7725ba3b7a8ed540c63e2209123b1b93f69418288b6 SHA512 b4f37786dc85e0596e2b7b261a5a9fe0265bf1651c39efb358dd649b926b12c3093f307b98bf0c4df3899f0a7cb1854f2596bd5c3e22fbbef42f912ab2eb5043 +DIST num-conv-0.1.0.crate 7444 BLAKE2B 4f5c4695006aa3ae77aaf5c55999a07d8ddfab294584fe10d73eb6abbb3f551846646156581599f966a28c74d80d3ac4373c49d2099991f7ed9edb56d36feec4 SHA512 7884c0c6599c66e40b9a79435e1bbcec60aa7e68b59686922dfab19ccbcac6a6e54f208cfb3d5a8a12e86e4dd67e09977d60b69ef6940e308a28256733f36100 +DIST num_enum-0.7.2.crate 18571 BLAKE2B d68d127db218d8c4a34849cbf64a8dae823e9404bb4231504ecbe02236d04d96ac161c3dc6e400a05fb458e42bb24418ff08f937335d37839b0f9174e3a5725f SHA512 a002a35079c81eb39945b3b2a903c1d904924c8417e12f54b9825ccc04a2f1ea1b1b93ec540c746926536851c2f6a9aa71be3c05a29afbd5924236b3e7874389 +DIST num_enum_derive-0.7.2.crate 17090 BLAKE2B 708f474f6be67cf1f3a63d989b6e84ff33a165f0fce98a2d82d99eee71970f2bcc2c9b58395049d0b6e7e089446a9155ae6b7d6621895326c48049416b5817f9 SHA512 f3d825aad4a04bddaa42d07ef4dbc69c793cc53999cc2b32ef49fb28499cd812896e0c5b89b9118d9def495de0caa05e473109a0937876da4c1a628964a8ba6b +DIST number_prefix-0.4.0.crate 6922 BLAKE2B 81bd3b588c788e6865104e5ce87119b5e0c5a526042963d52cd582ff23c2f8c9f32b4c445ef0397fc402b6d047e031d8e2c67ac97e191bde22e17662eec3a554 SHA512 a43b668d7314218b86ca7451daa9dfef71f6c9f6616bc34c12d94ae6030f182bcca9da83905cb46f3d49d0aa81385a787e92e4f3ae239658067adc249f8174df +DIST once_cell-1.15.0.crate 31460 BLAKE2B ae4481883865abe6a684d63520fb2e91b64d6ccdd0374464200015640122bd68b8a769309773226c8a31d0119f450ee821a2bd35c346fd86adb4474ea7c28fcf SHA512 934a7c3631e9ca4fa78d9577b6672ca0b2f926a8d6c3be9542b906c5968033446f98f76ae6f368a1a5b92ab9064c31a57d74ab6d2097108029a7ea951541ff7e +DIST once_cell-1.18.0.crate 32969 BLAKE2B a08d5beee50a7add28bd9e50b18709e7b34574f0f55f80909d5efb7ac5917e5f30bdcf3fb43ddd0a4f420a427390c7ffe1cc1c7191a3a1d939bc6e3139e6eef7 SHA512 9328968afdf3535b2d9e0113d75afa725259d76994ef2e1948ad7efa4ec8a65bac7cfdc31b749d5cd55ad4e28d2e28ac57b871e3067b89182453c7e2413a13b8 +DIST once_cell-1.19.0.crate 33046 BLAKE2B c14b374eaf4ac0f60acc2e02f7bba270a0e8e0a6978d749cd3cb0ab3eb26907e4fbea70dd5132982f90290381ed18ff8a87fd530f1415fabffac864f157ea380 SHA512 4154876afd34a699ee650d1a8a1c5ee5a25f0ebd9388b8bef2564e33629fae68f113d7507488c68abbe7ea1acf9bbc41813cbbf3ef3e464e3f3b9cc7a51d870c +DIST oneshot-uniffi-0.1.6.crate 31794 BLAKE2B d5cbb1ab31f541167692541d8f1f6c75243d5b39ff9c2357d25ca1da5d7eccc3fd2ff7ce4dbaf246e26c6741d2e78bba036388c7c1d63cf024d476737a9bd3ef SHA512 d87a9843546626ae3d0d06f347638b62b4dbd34ae3d1a9651353734d7dde120e474161f8e45bcbed2dc9c9e708cb38e9501d7e40ed62c39f48026009c20adfea +DIST openssl-0.10.63.crate 270890 BLAKE2B 0571a214347f823c9079c1f6d204c62469235ced63cbfdb8494427aed8069f45bbb26b81d1edbddb3602c0bffd54d1ca96204aef8cb85aec041edf45d89889db SHA512 47baa5f2e34b622dff0cd475dbbf6772adf48abbcec5be1cbcafe2beb9060ae46a3d873896ee4b5d864da0b132f0efd956596c49f2afc650a44cff6af001aa56 +DIST openssl-0.10.66.crate 273705 BLAKE2B 7892e96dac3b24ad5622833b4061bd82028210f9f26ec9772cebb65905ff6e45da8b21ad1aabfb87bb5610f534018da6bd20c10eaee8c189dd08a7ebfbf12b4b SHA512 2f4dd6e40dd8aff8c04563517fabeecd5ac0d986764649cc9af9bf4ce25757a67f75655eee207703b46fe57661a216ff00144358ffcbc70525447a063fa086c1 +DIST openssl-macros-0.1.1.crate 5601 BLAKE2B 69dc1c1f3b7bc4f934cae0dce64c3efa501162e5279efd6af3b74f7a7716c04b6996b306b310f1c045cfa2eff2895314a47ecbb020a817e461c6d77d0bc11e92 SHA512 57e75c84f78fb83f884eeaedb0dd135ecb40192dad2facd908e6a575c9b65b38a2c93bca4630e09ea5a82c77d8bc8364cb2f5778cbfe9d8f484cafe3346b883c +DIST openssl-probe-0.1.5.crate 7227 BLAKE2B d1fd6a9498b3ab7f25b228f19043067604bf20790530fd0ab6fe3d4d3bc27f13e6e94d1e7ef49314c3663477d8916b8790b90427f74976143b54b95350895165 SHA512 7e560314150709a34520472698060c4f29689d4e608dc4dde146140aa690350d3603279c693367deeb0f21ab34ef61956143a3447827a2b7a3d578b9ccd6552c +DIST openssl-sys-0.9.103.crate 71552 BLAKE2B 4cc1ab93f5a444b4b985c84f6ae90f345da4639e4ff7c5502dc1ae59f842d46e3855057a7c05855f7cd739b5311f330dff361480ef2a0102fe46471506956148 SHA512 61b802f6baf918ec055be90ee47c69fe0184f6d9a1d29c748386192a11d4df115758961ec9b636126a6b42d7d8f7509248c59f7c035905558c4cc35b804a8eaf +DIST openssl-sys-0.9.99.crate 68158 BLAKE2B 59995535bc24f0ca67ea204193aee4114f88538bbd74ade7c22bc2ea1b0d7e41a79118b6d22917bd1e305a43c16f8aea095c635d27a56fc0481a2baa3092dfa3 SHA512 b91197583135c22d34814e6382dc4ad4be9c3905c979addee8688dbc52ce627815e719b9d0b365195335d4d665eaa79a406f89e4c19cef73988938d51fe2f4ee +DIST option-ext-0.2.0.crate 7345 BLAKE2B cbfc03e7c960fe3023512a4ad816d657b4f54f8ecbde9f9c4df4c5fee3b36b68ab463c67ad650778279e01c7ffaa63a0dacbd0c080c8c3d15b1611de0e71f92d SHA512 f8539f97b01af97e0b80fc96556002251befa60f8ddd19613311e62f9dc9834d71c22f5d8e7c53c4925046e38cdcf834c3c28042a4da862d6f6a21ddff8d8e56 +DIST os_pipe-1.1.5.crate 11430 BLAKE2B 45abc371ddd363d193817a339f9e1894ec6fd275b9c9d190283347bb023ec7686e3ca6a5f2bf09cd7ee6abb8843ae52410c203af2310bf3e35c280c5b9874ea5 SHA512 d862484e9a0594f31e45531fac9a892fe247c1003a9c365a28083c0b5132719fe6fcd7ed996716a4baddf1f8ec4857d62d05663d3fd7ecee5802005c55368048 +DIST os_pipe-1.2.0.crate 10615 BLAKE2B e00c9a1d668253ee8b759ead12708d75b180abd415444fa995c18107317ad9465c11af1f6be67dd8f64bc7d289a0e12096e9593af99c1052aca644efc5d83107 SHA512 77662eabc70f034882da4662c6f9def1796e6564f0965beae961998ed29d47ddae8ef3b8c9e612b46ee6ab907db49a6259f8d586156ea88f4e0431fa306211eb +DIST overload-0.1.1.crate 24439 BLAKE2B acb2dfa6c6c22ea95cf58079f6ec56a2bb5e297a055ce717d40633b789b0d005be2bfd6616448cac61bd032e74aa6eed212f1677461907cea2f7f7cf536c157f SHA512 f79bc3321f45df5e3d0e5fa9c4e60524e4e28dd3729a09956766738adcf99ca42c187a01d48701ebe23d39aee00a19d4a07da798edc781b942e866b339613532 +DIST parking_lot-0.12.1.crate 40967 BLAKE2B 940a112a066e3cbd15e2f6df89bfff37e4ece2194118618a96fa14871813c91798f93181ab0f768d3e1f3d60805508f216724013afb7e3da95678d0d951a42d4 SHA512 07327d3b737a913508dffb66023766348ce7f9d555c224a099cabb05baefd16a28e15fec638e3a148a5169dbd980c4541b0f8820ae9d06dfe0704482838fbd5c +DIST parking_lot-0.12.3.crate 41860 BLAKE2B d1899a1132035aaea3a784290cf4951ea3b36b2018d407e27d333b2a2ce3820e040d635009c44cb6e58ad07cec6565c0347af6f6fb02954eac2d4c348bb036f0 SHA512 368c17203fb5b9e4ecfd4857e3b1ab96b86da3770b8f21be392818c845952f72dde1072a10265760a62aa8a1dd65332bfd585667444e5fbb9dbe3280b5862703 +DIST parking_lot_core-0.9.10.crate 32406 BLAKE2B 25339d028579eb45a957ae5fdbac00288b1472d784c0aa7fa2953fcf9279c750d243ce69744993ee8cbe6899633e71e0a54ffc11e39247755685107f2f8dea54 SHA512 4f30fb60ded274d3154ffb00f6f50ac284b6fb97daebc1a2ac897ce97fa8e2ec6ff30cbdadf3b7419617a410fa7525f30ef5e580334e07d4420f4c0200a57389 +DIST parking_lot_core-0.9.3.crate 32256 BLAKE2B 79a1924a983b948a5c2b0c074452a7b2b61abda973d3bc8040d9153d34b378f0ee330e36aa813f49544319c479665d6328be71481f2e1e41bc94abb9bfbd12a0 SHA512 fa30db0fc73b268ab8395adb8bda35d12dc15363b247a95b7c4bb848ff9b8dbfb971a20f320b4feff3317d5b533c59b62152e4c652c1809a422c5671310b30df +DIST parking_lot_core-0.9.8.crate 32383 BLAKE2B 2f9666872894d1c85895437d1353f9e15be2bc8d004ffc8f0e5be95e9dd4b274797db3752eba1c0b5b6071c1b8a71e4857cae0b2aff1afdaa39e92e70be2e6fd SHA512 8d6dfdf661b0f7d0774cb9f61121f2daefd182ac8a2a0d24eab451febfbe1a664c815c163d34a7f3d15a54915a8e22e6c6cd10e89cb7d7598d48d81ad6a3c256 +DIST parking_lot_core-0.9.9.crate 32445 BLAKE2B 811d8de671bf6e0911cf0df7dcaee4fb03a3b223173a3bb8cee65a28724eeb7bac87f62aa7b1df5ea3fc93af3cee3ef30b83d06c6773d6b856a7e6fa5fa197ea SHA512 7f0df70f9f1ca8d3da0b9dcc96e49daf05d95c3a995289266b5333f68818d686d32b0c733dfe3a0f62da78fa45caa843a963923b2d0c80899c33413dc749c032 +DIST paste-1.0.14.crate 18157 BLAKE2B 35e8548611c51ee75f4d04926149e5e54870d7073d9b635d550a6fa0f85891f57f326bdbcff3dd8618cf40f8e08cf903ef87d9c034d5921d8b91e1db842cdd7c SHA512 3a793f0e5e773a7f7defc798a4c17ae9a40d715144632ea6cb0a8c785e14c4212046491df016bb9838281f8eaf327a79f01c1e2ac5f26785c028bc880faff9ee +DIST paste-1.0.15.crate 18374 BLAKE2B 69ee7def55e658a9aa72405bad62325e8d6021a4989fbf11c88d1bf05fbac520f7b04d467bc3c6eb45043a41119f65aceecc4a6a1418a9192d73f33134545062 SHA512 5026d3ec7141ec4e2517a0b1283912d0801e9356f77b703d954b379439b8d85e3886d42fb28f7835edaeeac465582da14233564fb010c71425a59c9e1cbd46b4 +DIST path-slash-0.2.1.crate 8821 BLAKE2B b3564d0f689ad1b943d132fd95adf2ff654b61f182082bd22f7b8f11dc9024cae8e1b9f3551c4424509db17aef899efd3df96a67e1cd588ffe0fe385c957b361 SHA512 c046707586f25f13d2f9fa452ea340198f6d2e6333ca3af806b9d2d1a61d46b033fffad60d1632ec16062fa79a3710d695b923b831a7db52602b728ed31fc3ab +DIST pep440_rs-0.5.0.crate 42582 BLAKE2B 667d172ec08237e40dbdf6e42f4ddf3b018a78e181ff50a0a240c7138f8d414a4390befa6cc7df41f489fad49703bb5e75b78e9be4d4d477b20e552ca8eaf896 SHA512 dccb69fcc8c85c3b02922964f24a0e2200e3b1649600c175d75fbf99d0a858b8d59a21d897429134199a6d2877163dcdbc1613e4eebaa174ccb26824b4458571 +DIST pep440_rs-0.6.0.crate 42496 BLAKE2B 46d1ce98ab48233799acca4e1aab1d4837ad0c4814cafe6d971a39c5d1fefe034896ce1d468ffe77b9a61f3c52fe7a1ee05e590eb4c67c718356e54da9349d50 SHA512 4c50012b5d04227d0dc8cd919b10b774d7c1abcc08bc5d0f9e7817c846ae906b9cb60cf2b0d65c9ca37d3b5b592e50d5847aebbf136366b4032105b287167b8a +DIST pep440_rs-0.6.6.crate 42621 BLAKE2B 311ea4eb85b1d3b450d1a757627956ce15b2bccc96d0d62577aef63f3cbd27bee8c36291679ba36db1e29d447c5d0fbcfc0d8fdeef16613974a9890afd7de34a SHA512 1843649bcb93359226f49a1479075e1ab1409671167313bdb7f4999d9a5941ae1814160026ef4fe6f2ed52fbfdaf75c8b4b6e1e86fb0473774520ad22eb88186 +DIST pep508_rs-0.4.2.crate 33741 BLAKE2B 4d80a7872300e364cd78d7d8f635e3bfc8b22113c9a3226b1467f8408e5960b68eb97cc87fe9c90e50dbd93e07fbfc567d5219ddceaa0e1c40aa47544d8a219b SHA512 4b5a437f4dadb391d9afcb7a9dfac786d0dadc9ee87cf9cbb68644243d000e21272839c3e42c0044138afea5c9d20233fe01a3166384b6a54324e03a3169faf1 +DIST pep508_rs-0.6.0.crate 34138 BLAKE2B 3eed7514426f0aa1a17be19727cd0dff745a6f2caaca2beaa29a4a4070722bb7e5aae72d9aa0ff8642e927fa5ba6801cb680f875c9ad5c55b648b503b7f998cc SHA512 fe7acd77ea677b7bf2096d7f9eeddd89478becf87b05bba604344c1ecff876a7c7feb75ac2e1ab1d39b2165905b206fa3877269e69aa6eabf3cf6db1427dbeea +DIST pep508_rs-0.6.1.crate 34148 BLAKE2B 95caea07ffa19695dfac3f8c32cbcea0753a239c41719b9742c2b489024d06c836a04445ebc24e958b456794df52fa8ef0fb089a18d837b64394d251fe313bda SHA512 595e808a8ce190430b1d31af31156971cb5cd922629ab36d627c45ec27a2137badf4c4e6276702efcacddbe3af7a1c19d0d887b482a41e27d961b5e0677b57bb +DIST percent-encoding-2.3.1.crate 10235 BLAKE2B cf8e2fd7b359a05b7bdaf731f9ae84c7fe6f468a53482eb2db7f93dfdaab64ac812b3664899db260055a93449462e6d219c695942fc5b030517b197b4df9b95f SHA512 5951ea8315e52cf3acfbaa023cb9e13a136b114c54a7da0bd44619ae24cd2159d4a96469d7572a2fdabd94e19513a033387117d7ca81d0eb409fb383e4acda44 +DIST pin-project-lite-0.2.13.crate 29141 BLAKE2B c434a336716c9cdd16ebc297fed393e9106ef167a693c4aa0b12c681e03141b8ba3cdf64c310916cb7d5cc43cbbfcaaeb39bb5fb1e8b3efb9e94a3f72af914eb SHA512 7f12595d751d315de6c0d380e2f501b74154661eb676987d2cab6fdc956091a68c9cac658df45dbff73615e982e6ae2ea138c09ebb708cd6c351f0d18dbbdbee +DIST pin-project-lite-0.2.14.crate 28817 BLAKE2B 8e9875967059faff399fbffff82cf8835982c46ea8df942acf50b038e3f500e04d3d8cde39da5a71ebcc38b869553f8c49830e484d1109b353247a4cfdeda89e SHA512 f90a6b9f5ab8701718f72677a4f3597c1b9f32e5fa53198b47a94696227ea37815997599abaa6058b217c5b32a94602582c6b13fdb66e2d683bc98921de95293 +DIST pin-utils-0.1.0.crate 7580 BLAKE2B 457e1287202f16d1873b24bf4f1de1828300128c4ba3131758e64f9784d36d47365f22d85493c3a85d854f0d8dbb4c6cef3a0f5b064014dc03943e58b7ba9178 SHA512 828422b8440cc82ac6b0743e0112fa7540d437aed457564999092b1462cd7672cd6b1f0201b67075431aeedd3d9c5127468a3dd028744109944f7f023c82fd70 +DIST pkg-config-0.3.29.crate 20563 BLAKE2B ed0559b0073890911fb47742743b2586123bf9e9b594aa0d5b2c419c6768cd37e25b546c21077ea6cc02823a679b302aeaaca6c7fcaf9aeec615dd08f53a1f6f SHA512 bac7dafc0e10bef40e427c1fc0271d1a26acb2f5b1cf7cc7a128f4d4f1f3110529e45057b71cea7b0f6ddff26945fe08962285ddeb22b54639e44a2e43af698f +DIST pkg-config-0.3.30.crate 20613 BLAKE2B e14dd544612f74b038bc7d279d629034237946c261e3e97621d6ac910a12f4fa4e75932dbd5d3339e62325d0ccf33002b07f04b0523f93d2bd3b1a919841ba66 SHA512 e4bce232e1e1cbb17d1c08c3de4dd12613f5a5238f831c2a765b6ede9b494e647d2416a7d9a0c926104e24066dd1b38df8df98a6c55d62f25060f80eb33d064d +DIST plain-0.2.3.crate 10664 BLAKE2B b0ea38fcf6d4f4e3ff91d572b5639f01eac4f19b2c451d27bca49d994a07c6f46118cd58a1b86b3d2a61b7ac9e17e8236f1cc98414738d8c86086d37e0fe4d35 SHA512 6909e4b4b4a0a49e6a226d7393b121ec04beb8a13b1652c23337eb09b3c2e5f202b53a7663dfe7828dcb32c3d18135b514e9a982967c188e127a63b6cbeda252 +DIST platform-info-2.0.2.crate 28443 BLAKE2B f6389f76c04954189a6ee38eca506659b7597b99ccf6c4eda8b9325318de52b40447ed5474062002afc7fdd8411c8a56b9e4a0b03843ed47d54ca9b37e96227c SHA512 06f36f3091baaa502d33322e5e77d4871781144ed4ca33a3097c9611cf78e2e91852b8be59b1869e2e441ba0f8a076d4f25bdab7235e3324247d1b5bf49967da +DIST platform-info-2.0.3.crate 28454 BLAKE2B 22c60f2db10908c9dd0e07e74ea40823156e2d795bd6e3c279585a424c692762c0d18885c0c5782c3e6caa9a91ee6f3adba2279bb6cd0448041a667a82404fc2 SHA512 305699107d21673ab22e56dc42752f85dae93922dcef93233f355b73838e54c2d157e89db60ffdcfd38f105ca6804f76c524ebb75c4f94845ee0320c46c69d03 +DIST portable-atomic-1.6.0.crate 140689 BLAKE2B c91d06e04a87c9a207233d8a850859aa1f5cc43dda8aed34511c3fe9641c27412796539ed045a58e649d2a0c7d71100b6b2d78a0c662fc061fd961a652ae8722 SHA512 b27cf57655a2f1e2d6ea7b45d80b4f9920a836e462f132c50dc1e4d314e162444309de1baecf45dad2defc7a5b99759165e54da9fe759b24092f8cb8755c515c +DIST portable-atomic-1.7.0.crate 145385 BLAKE2B 7d9622d636677e3adae0f909405090318a9d6189fc18683ed21074e9360f213b44c5213f3561e3dd1f642547c2c2e6682b9e1efa63243c1f12636bb11bd15dbe SHA512 0849edaa7a1f9ea66182443e31691e7839c857240916521bbd6009b5e692b13f5b315df36e656134651386bc50d895ecf6155a906750009514cad8bfc7e57fe2 +DIST powerfmt-0.2.0.crate 15165 BLAKE2B a3e1ce63f5866f75526eeb749bec6607e42cb495bbb953082cde7e98e6aa429ecaa41889d98ff7ed4cf5031258b4f7e0553ff8fc435b3b6f8b4ef2b6d53d9b61 SHA512 0623f92e4d6ab284b3f6dae58220d79d9185df4a738999d68040c50d72fe0380d70358cb622f079c629bab53bb03c6e085e165d5bddfbeea84245864fed90029 +DIST ppv-lite86-0.2.17.crate 22242 BLAKE2B 48c4a31a3b555fa37072c4de083580bb769747c7668748541af472778b5b58c3e7ab2b5e178760f542f973774f09910bdd4058ae5fb9d6b10c103eb76cfd0d3d SHA512 539d916e7e5869d832045c1aa88aec519bd000227f9b01d4dd0bfc9ffb640d5f5eb21b05eba718174773c97192a655ad3cb31b53ceb914dd19179a6699b3583a +DIST pretty_assertions-1.4.0.crate 78846 BLAKE2B 68583c49f81ab0cf5b90f6de10ef3aae9b525288fec25f9d006f2eed0877c0fa742dad5f878fc78233b54c0cd32dda7ac1f7161bfb475288d8858e8e40aa9e1f SHA512 f76d38c787e91b3739272e3bebeb9763d312b85a43cda5e1311ba8d6b0e4da1ef25bd66208e772b1cf56a34553ee560482b5ad19c5290608b2aaf9c0d0f0e995 +DIST pretty_assertions-1.4.1.crate 78952 BLAKE2B 016df9fb2f24304b68a6bf4fc8e144387f07a5a15fc8d92757cffad11b4a00e74559abf597d4ac8619a3dfea705c82df1b8c8620c5f32c61ea8f212fd9cbf9f5 SHA512 474f77c61cc17bbe9914c56b98a80e5918450205827cd059d693c2d603ff61a0897cad25dde645cb495200e61ddc14333d15eb8bf2de090a2eb68deeb9aec8b0 +DIST proc-macro-crate-3.1.0.crate 11084 BLAKE2B 9a9d02f0f34a30668ba94e34d51199c332209c47fd8bef28c452924f75984dcf3aef2c92c4ab3fb03205d589e4f773d960064b4d08fdb2480168f10b84fafe98 SHA512 eb5ad763aa700f2cb1604c32a4bf2fad499a03ad868a22d06b0697b77875b1cc13c739fcf165b2bd547207ef6dc3bd13ceb75e1a59c596daf916f356ed27d8e2 +DIST proc-macro2-1.0.66.crate 43575 BLAKE2B 9eb3e816b00fcf625c280ba14ad269f5893d0523473a24de07c21945f6f932fbd08efb3c339b35d903245510e3f065e1478439b024a325f2bb9f97bc7bcbb18d SHA512 85f5a762f9411142e5ac28144bd380f07f0633ed2e44d8a2545be9fb8f42abaca6b5d45631b4be83b8e8b9beca7438bc52f25615c3a410a3a1249474b1aca407 +DIST proc-macro2-1.0.69.crate 44271 BLAKE2B 9d1531a0b123e6238363d574bee03ad050454b65710b9800c12597f3a9ae2f9bf50c617da0472b7ac0b549afaca19c546ccd6519e648598500efda9c0db2ef6d SHA512 d197cbe9b6100c3193a01fd7dd6b4e49d440290012ababb5d9f139409f0afe816f213d67a03abeb1f3227228e0a1f2446d1dc0a2775363a15d1237c38b45d6a1 +DIST proc-macro2-1.0.70.crate 44343 BLAKE2B fff0dec06b21e391783cc136790238acb783780eaedcf14875a350e7ceb46fdc100c8b9e3f09fb7f4c2196c25d4c6b61e574c0dad762d94533b628faab68cf5c SHA512 ae9366856853f7d96caf7a7581843d36bfc7843f8683897b19ffc666c03b0b1eff502ddb18ca4c1c1a239a368f03f6cc258b0e2795f64b61c6a31404462eec5f +DIST proc-macro2-1.0.78.crate 47158 BLAKE2B c56a24fce3faca9e04db7965cab552d2a976c3764df0a84179b5a89d1230ab355c777a82b4c982e3945414f1f0478473a88821dd176c32d6de394d73a26adb9a SHA512 11956fe03a2e77a925cdff2c3c8bc8804dffab4fa1de963a128fa23f4189976fd2e2102bd346b92c33524beae320b71dadaa5213695a3ec638404196e14fa769 +DIST proc-macro2-1.0.85.crate 48988 BLAKE2B 236f2a07c758d0d8628f003b70d4b25d5f0d2bd8cbd3955fc4262d7d9b271c6571eb0fc45c95fd816b426a84ed5ec5dfeb81d8041d4de955cce6f3b9fceda1f1 SHA512 54c61dd0581bb5802e077a58fa41f113aa1fab59026478268ece293f2643921b7649844c1675a21a3a21674cdb3ccf94928e5bd069a02bf6813ccc1114d37262 +DIST proc-macro2-1.0.86.crate 48958 BLAKE2B 4b89e07f23af8328dbb34fe2b3f1b202f1e6a3885a6269740a23359b41bb4099ac2484565d3b2b0936261689ca525785ac620c766997234fd8d0f409e80e5ea3 SHA512 1cdb7e22a35ae231d880c9420784c9acf97bda2db258b3d34aae5061dc1858449defe19a49e12c6a4173906aa72a4115059ac2db0fc760205fd2ab8b5b414434 +DIST psm-0.1.21.crate 23126 BLAKE2B 5972b4bad729d3c8842d4d616b1a469fd59ac7cecac5dc5754f084b7f2c623f715f302a9132cd146f48f323982c837a63cddbabfdc97c73ba88ee60df3d036da SHA512 33e34bb30efa5ec700c135e11fe03447d56e6f0dbca5536fa8bf9ca2c605c65e2dfe0a2a79a0bbe08eb2d2a37e569e31def340e1187bc25060c2f0e6537e3e5b +DIST pyo3-0.21.0.crate 500599 BLAKE2B 8e56a264f6cb8b8e5cfcc1854e3732edecaefe874cbda4db10742c4865a876625b723010ec6d2539ccbb58643b26c5d03522a0f3d03121af09632f3adb1186de SHA512 90b551c6ac4867245b2667fc4a9b74875351aa0417cae6c24ecb4cce1b2d4ecdaa7e23a07bf188490a25b6033985f8598b3ae202917e9bed6f4d72168a5383c2 +DIST pyo3-0.22.0.crate 535742 BLAKE2B 772a4f8b718bbec32faa3dac4cad07a5b452fb366280753c3316d932663bf367192483fb5cd0bd405321128e67157b982eaa89264685739a141e021f0f7e2b72 SHA512 44e0237fd3a8d4c7b082c48a5c8a52d8f4cc4673d134f680e29504bb46d870015fa210da34de4c1998defbcd4afdf2aaea4e148fbe093e4b2c8b0d064cd48da4 +DIST pyo3-0.22.2.crate 538342 BLAKE2B faf347695117f9fe0ebe5cd7f6aa1b0dcfe718343875d6c06438046deccc1075f104d2a2413dcda41ae9827bc363aa147057b45968f6634f577a6a4510a4bb8e SHA512 e8bae09059f50ffe477dad44499cedeaf3a734665f0fd8e8bd4b44f48578d21e4bdb8d55ceea00c5a27da750761842ddf89cfcecdecb2e7a4a17ab192259be9c +DIST pyo3-build-config-0.18.3.crate 29137 BLAKE2B 5fa645b64f50a078f38cc10a27ed52bd7e7aadd8a069c05ec2963f0b7c869b94d29eddda97cc31d200cf749ab8e2cd9cd1ea00e75620287e9187745ae0e100a5 SHA512 7ccad5f245e84895e147389f05270f32d12f81aba46bcd0dc184b8d62af2ea579efc50383502efda40601c981c4dbcf911aa7d8192364caa2e177ad939062cdb +DIST pyo3-build-config-0.21.0.crate 30535 BLAKE2B 71bc1756e1640456cce58190d90f7c1059b9748d9d72a122dd4e28c74ba96cb9fd2bbd80791d3edf313349cc0fbaa669c8e9cecfc925c9828ac794fda17a6ed4 SHA512 ac1ee7389fe267c28ff67f5d6a23bdba57ad2e0dff16e7ef38bc2bc95d0a2a4aca0b1fe4cac8510163c6c5a44bdac128f36d7b34655dff5f8e690db38e5edc6a +DIST pyo3-build-config-0.22.0.crate 31205 BLAKE2B 6b9a0de5f431bfc123628c67da040e146e39353d7b42d8d083e1911929dc420622f8a1276229d89b7780bccd02a8e653bcb85bfa51281e72ddfacebadef5277a SHA512 50341f4e5134a275610a5b86e833d1963a0726c2ddc14f4742053c60ad336ee209e73441aca46c8670920ee47a81c76bbd3f9e6412d253a5b389692ff8f3c1f3 +DIST pyo3-build-config-0.22.2.crate 31225 BLAKE2B c2e6a3d3d23b7f2f51bcbf1214ab20a298a1e62f85c9af3dab1e77b09f20b657b576feefffb18eb49d438f0ffab525b6bcd1086d500601c327ffd4fd24a719ee SHA512 644c82d30bb27051557efcc9789a81380a64e29bc62abf97de88f42c3791dac74228c7a7d09e0d46d14f07c0475f0bc03fac6ed1367b9a616153e8820b94cbc8 +DIST pyo3-ffi-0.18.3.crate 64474 BLAKE2B 32bedfb4c7d88e539e958af0dd48af311934a817282a01f860af7cd824fa1e3825c505463b78cda57541bea8ccbbedacdc0f67bef686e6775fab3787c26c6d2c SHA512 55240c7824ad1e5c69e05a31ec03e2064290c89c4c98f06c3ebc38c311a10b1690571c977a103790ddcc9623ac42fbf525fb028e910baedb9acafe39fd6e4a82 +DIST pyo3-ffi-0.21.0.crate 66158 BLAKE2B 40809352e9df9ed13f833a73c9d50f71e63591a5b4680fbc85b2c10fa5d0ca65b793d6f467723bdc47887a38536fba4c2b2d9ba52f5ee9b2005a23d98778c407 SHA512 4405a6dbb06e739a54056a70b072b94b1181aa5ec06515c32ba76962fe4bce6b2b63cc179b77d3656123eff5f60e650bd6efe026794ad38d37e307f3653a3f96 +DIST pyo3-ffi-0.22.0.crate 67420 BLAKE2B 65e4ed1a1ce854f37380aa23637a494226b98941b9e3f13eae8f627db0fea248c3cc93c7e594090407ab169cfdb27ab20c47f7004f2b4646103ee34da9a55f31 SHA512 cede32dc8025badcdd6d00b4a1204c6ceb5ad30fa0b637deecca669f2ee2b8961f88d9d867caa8cae59f498dc4e1c15f3b4049c5f47615e215b0f289fc560bce +DIST pyo3-ffi-0.22.2.crate 67749 BLAKE2B 0a4357d5f4fbcab9717d58b7a80b63a63bc329267d4725136c4eac7c0101095a50e5f840638dde79034e5df99c4f46664cfdc2ad437837643db5d475c5705cb3 SHA512 bf8b83b4790832d99de8c6a61a15a43fc189505dd843011933305f7f93c4f5f4849fb00cc2a6fa410b788645f8ed8c0df61799cf801966a925abb9756b1ab579 +DIST pyo3-macros-0.21.0.crate 7917 BLAKE2B 3b7471486cbdfb8a9970f3aba9ad88dae9a2c620993f7a9cb6a3549e170fe9412318020e6c905eb35678d52d65a733e4858c30d33b6928dd1cb1f4f6a037c2c6 SHA512 b842f58813a152055f987ac065d3f38229a209c381b384160a1be49c271792347ffe97fbc6c898b120553e0f6f57743f9488cdc342a5a844fdd89bdd637515f7 +DIST pyo3-macros-0.22.0.crate 7889 BLAKE2B 0b61caaed415023341dfd675c578e39cc3e5b2a08eb8c439857c81cf6cb895837f5df28decd7c08a3aa365411ff33a97eb5fe2f20e18427bda133f7df53349ba SHA512 ed9e9d6322fb8d3fd11114899c3ad84ebbc5b5eba58e5aabfc7f9691f02ec053f1c2804cea93d21f2ac9332f5b719b7fee9878faa95f21eb2a2d86f9050c7339 +DIST pyo3-macros-0.22.2.crate 8136 BLAKE2B 9dc97d2f60581db1b8ddb562dac917069525f297fe2cbb9aff3ed34d5a08ea43c112c9c7a450539da3536d753778b5ca506dd1b18e1d6b8a3649fc098e7af439 SHA512 f4f4f6af8dc3aa4bcc1698661990ab2112391ef9502e9f71d86e35bd10dc4e1be309102ebb1b7b32751817a6033168dc0486fdb16b35c626101e69f0de807a4a +DIST pyo3-macros-backend-0.21.0.crate 57562 BLAKE2B 12a25a2103d1c4c2e8da291ea64f202d3237eadbf55d7ce2bfaa8b6846df098ae5d0456cc9cf409c16fce323de127d60e0f5a458cb387198f604e6eb8e2a9dbe SHA512 e65b2816464ac189616f44065fbe45156f2aa560e880f0c8b49a7d097ac1dd278a9cf0c504b14de3ee550f0604da5ec991be6ee6fabdc53cef54f0a2f0a8d849 +DIST pyo3-macros-backend-0.22.0.crate 64837 BLAKE2B 4961b8c8720bfc2bbd11089a658d64cb2b1e43e150e622d53490faec3b905344d256b2092238ebb1dd92290583ee7d04a12eb5759bd55276e7042e1c948c71bd SHA512 09496c7285b9faaad820cfea237ef602569de3adeaa3362727182b0cd1c8377ef55c0c28f14eb703ea73a86c94acbdfb1384b44ef32b318a76c730a0430ca233 +DIST pyo3-macros-backend-0.22.2.crate 65620 BLAKE2B 37fba9ff384373418d3a7341acafb8e33308a64e30026f828693a37c32ab4a74d058f2db84d00467a20f9f267c96fe54c0f154d1ebbae92490e8dfc0d29c042f SHA512 0517080c0d5d4ed8136521fd37aa3a192c2eb8cab58545d8543ee4df9cd0dcea19fe0678d5ab90f05fe3eb0f4a86fc2f07b76f2e12ac1fcf7e7c195c2ffa4fd8 +DIST pyproject-toml-0.10.0.crate 6072 BLAKE2B 672d391f2510f9eae63431e8d3d09825f103672dacbb51c5997d6d83a229ea3a877a79adfec0924ea48cdf143e915a2ff308a5865f26826d459ee1e7f4796f6b SHA512 9e8bd5572b86b9e9a27aa67a7f6a7eedeb9c3f190512577872cbce4fb52450a3966a3576a695d3e54bbe1005f9f6f1be4d20db3af4b354e294af8e8d50b59095 +DIST pyproject-toml-0.11.0.crate 6083 BLAKE2B 187c00dbf90bb32081088efd986d2072d8f8f35eefec683403f5a0a509e4673f443293051b7d828a1d917fd0f7bc308852a77c8bc9b4832d361e32135e9c0a79 SHA512 05a2529bf3ff5aab74ed86c71e1a0a2e8247404e2fab2dd24c04a7e832325c30da915d43a1c2e47ed5143824c24d4c961e19bf078e60687faedcec3a43e53b08 +DIST python-pkginfo-0.6.0.crate 211883 BLAKE2B 3ab285b3b48961e0bd3bc746673c32217ed548dca163cb1c6ed7fbebb78a152c60eda0573d95add08f149d0279c7abfcc9e8eea2ac07444e7c1afa7926912dc7 SHA512 27c1e1a8176475a4a16517e02ad723669b0be60a7e1ccc38e0461c2143985098386e829a112e61c65f61b09c249dcd26a1b35228041c91e1face325d1d9f097f +DIST python-pkginfo-0.6.2.crate 211952 BLAKE2B f5663f3850457b4abf04f038ade370838fd32de30362a9880f626fe8e84e56227a868eb0028675ae624af47a169f93f7c199de32d8b31df65bbb160b31713a7f SHA512 bd028bab20cbd57ee0c7d469ceabd923f36bd4fc44116cb0e510c1ee2a1ee6aa8cd4d5efb20ac184c1e9d8a91ffabed1577e76e7c488c6a9aa304d09773219ca +DIST python-pkginfo-0.6.3.crate 212171 BLAKE2B b943b04300cdb75011aeb2eb6eccbc21eebc7f5ba17780442d990e76797de81f01b1f550dbb3cc4cecd555ec6c7e66c7d1155b2d4bf8d985bcaf4ab06bb6f427 SHA512 71c8a51860459f0a63ba21d2c9da54a7aba0c65d8c5e7edce695ae1b220e33209b43b058ea8f064d56954dc099c0bca495eb7ba6d4458d582383014af94e1bab +DIST python3-dll-a-0.2.6.crate 56866 BLAKE2B e8a83d0e02c281d8a626565fe1cde1158726c9ff718afb0888298454762832d47117d7a1bfd4e3e471e82ce684cd8c36d8d7ee036b07748cbf09aa915c2e046f SHA512 f64be4ed3b217d6905df5787afb3d403580eed1bffc17a251e2c8eab61aee6a187460894b568140c4d38369e77fb51c4d49f6df9127786f344b460951df249d5 +DIST python3-dll-a-0.2.9.crate 66092 BLAKE2B 2c4baa31df7f55da8f1c6073525b4498bae7207ee38ef0eba4dbe58088609937a7d7b851c603ae62e5eb5361881e67a05d8c112d0a76aba5d99b13cdccd59d59 SHA512 1914d3ce67284f13551a4efefaeb9c11138fcca3d5082746282f64b7a36f732c6834766d981f27d862a61410eed09b3d281e0cab8cc1a46d424d04823ffaee35 +DIST quote-1.0.32.crate 28037 BLAKE2B 7b243ac7929f3b2e1d91a51a2dc2b11dd29bc017be9db588c83bd137609e2f991a4f3ff8682c7c11c177153e517c4f818285cce3237f435aa43ad0126c4bab6d SHA512 13cae36920dcbd0ad1978be63f20b35b8424d02b4d9992032fa78c7770d61d1fa7ec1532a48793cab48e703236b7bee7843041253b9e83700903228078b4c025 +DIST quote-1.0.33.crate 28090 BLAKE2B 77c4b166f1200e1ee2ab94a5014acd334c1fe4b7d72851d73768d491c56c6779a0882a304c1f30c88732a6168351f0f786b10516ae537cff993892a749175848 SHA512 c1e76c3c017e8554eebe309f8167fd56fce931981c06798aa85a0cc6d64a9cba6ab103f5a1324e69c6f9ca5dc47a8e31ff2e847850542748697afcd265b5939c +DIST quote-1.0.35.crate 28136 BLAKE2B 81424245e1e2b94459df68bb3a9a866c6a364102b5e1d010ede9c5f8278f8406d7b651957d091c5914e936b494b0f6e9a6a1dd8b7d35cd7d7100f86dee4ec12e SHA512 f5314fb6af17cf36c228e1970c569c29ec248954a450a5f90ba9e2896d04f74904c9cec5a1f74325f2489295a94491eee4ce8fb461e22cd4b34e53f1f881efd2 +DIST quote-1.0.36.crate 28507 BLAKE2B b93495163ed205e33543ed45f084870240d479071d643704b6e348fb9ada6e1d8401893c13348b9964f4b6b17ddb96cb5458eec540f0d761655fcb96a4cd9129 SHA512 f1f002a912692f7ffd4912ca980ec57ff4aca3a7d9e2e42e9e3409e2105c9f59d86c05719f6af309bccaef2f8843b0848a6e3afda3356e045d8e7cc5956ae685 +DIST quoted_printable-0.4.8.crate 7132 BLAKE2B 8258519be27b010f73fc1835bff917442963601f22cd026d09b8bd12c5c66e691a1e6857432f1b47aa5e044a4ef890d60725e6229f7ce54cbe450900625199e1 SHA512 e889b18c92e34aa6403cad66c6fca00de75cbbda1b41d30f14c27154d93961c973dc77991e36f869a6996117cb3bb08176a4c85f7f5e0a06fa09ab02e75a7460 +DIST quoted_printable-0.5.0.crate 7604 BLAKE2B 470c2668e1778805ca855f3c65ce4b9f35148bbf4b4556e846f04b0fc263dfe237f65f5d00d64472dcf384003ff077a13ff0c36a1ead38cf0e1073707add9bac SHA512 90e4d03590b678ae39a9be7157d1943e670e44df11a69ef5866b06d8eda772943370c66e41d1d25aaf877fb3a55ea3c20b990a243666ab934e168feb9a12442c +DIST rand-0.8.5.crate 87113 BLAKE2B 516f26bb2a969d0d79e957818133f35d2c0b4d9f1b401098ea23c5b80d27599e842b9298c0c5e46e2a6cb6953857bf8a9fb71ec9366c5ce6708cf17df14f179c SHA512 8b33a8988906ba5e2057a9a84bdd11f867a5536c22f5056eec59ed4ec4e3a6da2fd773da4c0510d343762e5a4ea0f007db4c4a7cef87a47f90e36c1a84d86fb2 +DIST rand_chacha-0.3.1.crate 15251 BLAKE2B 645771b2c3e274f085e0837a20306b1d59f6e9032fba8eb38a6d1b30180d15e2f89ffa2a162bf6358da41e030098242d81e71dab4321980d0a4f6ddfc2974ce3 SHA512 8198c580b1b9b0429758ffa49cd8138fa3ce724f0dcf73c767ea7e55611d6a2e4c7cad9950896510def500ce4062b594386c947ac3d89425b4e5c9b04d0b8075 +DIST rand_core-0.6.4.crate 22666 BLAKE2B 8b6b66d50aade877f2779c006f8038db450f808c66d73d79efa66c4178dc03db06f12201bf0e7930181c4b0f4030c49b20cce6eb7839763cf2217cad9710789a SHA512 36c67eb845aa2ccca49d6d680f28d418229bbc5a050729e487fe6b9f9f384fdd7b8d67fc6508b90b79ffb3c26688e72feceb3ecae57d3d7f59338aeb62296f79 +DIST rayon-1.10.0.crate 180155 BLAKE2B 16cb706d2317d8a349394c521ec5ab550290c5ab2a0a0dc24f0282fa7eb01fd1351a7dc8b5af3a55ea321e6526fbe037fec3cf8b32463166a082a6e417a51fca SHA512 3f628c58f3af3cbd1f245ca1be9c8393eff41112891fc4e676a2b9e26b6cba7cb80d7b6ce46e75bbb65e42fc00c5c0bb6b6a4b59092882f03febeb31f9cca5d3 +DIST rayon-1.8.1.crate 170448 BLAKE2B 982f7ba7d6a43956e6f438921fea2e40d3b398f4f72a4c89f55657aba6aa0d99912a7240b1c32c1dadafa9852adf440e3153a3f0cc56f6582867fa2794bb5144 SHA512 a83304be8334f5aa1c63468ddc749d8e8124c6947f1472320ba0bd4351c9ae582dba31ff369e9efdafdab439571fbf91b497c2370ec15406cfa810f5161cfb32 +DIST rayon-core-1.12.1.crate 70701 BLAKE2B a32eb9ae9a71b4f0881f7bfd5375aa7db5681f20f7e0b25e6ecb3161f2aad36b93026c1691d02bf298a48ea07ec9475a237fba457ed0b0b8624aebab2b4988df SHA512 33d0297b682f131c50e1eabc3be583211a5abe790301cbca91bf510e43d6714b7564ca39fab7c4bf6f02aa0df6bb394f386a61320f21ddb6bd7aea1372b5e99e +DIST redox_syscall-0.2.16.crate 24012 BLAKE2B 9497a52044458b1435ea16e86ee072e379b6b11ee31602ea72d6b6072a4a99426f409c2e58108a4e9c36dc193fa49c83951e71f4fd4e158eafff18c594dc01ad SHA512 63b5d876baaf99f5cf737679bc6ac7a9e3d8a41aa93f5c59416ce7e3841e2513bff678773553cfe62fb452707f82acc384ea63aec932a31bf94679cd1caddd27 +DIST redox_syscall-0.3.5.crate 23404 BLAKE2B 85aa4299d9816666bf576f523da5cdeae87b3c8fbb2af103e82258d23f73303c068a4b6c3ef4117ad67958cb31e41f836a9f59f2ce1bc52c23605e34399afcf1 SHA512 16f8f4766932bb54e4740cfdb4f0802f76246c0bf88c1d76c69c115949b124b625d8c3b85d8947073c2e9544f425aa16c10f71fabe3c03d29e424c47fe4ccdde +DIST redox_syscall-0.4.1.crate 24858 BLAKE2B c3301137a0b84e03b09d28dfa377ab3bea74d574a08cee21d35713b278d8b5b30ca2a1d73a0981baeb4644cbb88c86c8eb15ab3bb2692e38b93e6b35fab4e0da SHA512 073ed9d96090cf46eab9877742277a013c62d8da86d9caf2310b4fa868af306511936553579e01309f27067d344226cc8dc5e3aef01d9b900da2febd33848f8d +DIST redox_syscall-0.5.1.crate 22536 BLAKE2B b7766fcf35dd865fc98495f60da54ca9a6b4cff007f4323d1c63de5d1152766aa5517139b5ec50afca39d934360c701a180c4516feccbc2600085d5d72dabd2a SHA512 0952b5f4f79f2cff04b4c21d964df7b56bc0cbff8d8a2a9a7d38ba66fd69cbd0fb004cd3d8ac6feadde8d9590858cd7e1763da7e4a5de840cdef42b1b6f1e460 +DIST redox_users-0.4.4.crate 15438 BLAKE2B 5f44e9ef20f1a6c8b22239838f8f6a6648dbebd5b4386b3a2c417e39add8c4a0dc32e4369b8bb4e0ea17678140f596b9bc981b1d56f06de6a38a503600420481 SHA512 7c208116d1171b1f52f22aedcf8ad00076a3d1f062f4018f4a9f5fb2c38d7ed83258589062d1559f64e43f3e2a9ddf789799f57cf87a49ad8a37463ea09aa269 +DIST redox_users-0.4.5.crate 15514 BLAKE2B 9fc9d9c4875ed711efb75fb08f345b5f4f0667717d37710143742e48251a709c53760bcbc31ce13e6432672f9417be429c38c2e77a6b786887841714290a1194 SHA512 7a25cc91c9d1bfe537f20b83255990681d136ced5aaa7aa0cdb1b1fc024ba36aa1fb75c335c768a85ee078019a9ca2460efd911cad8ae6fe8b0385fb171aa4b4 +DIST regex-1.10.3.crate 253101 BLAKE2B 390ebb00bf5430048412883b672d80737e783fd36f40895343cb38ef2e26e2713418c2fb4d66792bfd3be4c990b4518ba120de229a72cbeb7fd5c2af325fbcaf SHA512 d090898465013b0975a6de87fbdcdf76b4896578056f4da83424bd5e7832547a3d8ace643c379c4f14700a0a88dc95950a38645508d1675306c377879a90cf5d +DIST regex-1.10.5.crate 253805 BLAKE2B 9f5418b577209051640c3614a98b15604a1e71144763a6f00caa7757f0ff67fd833a7d14fe9d6acef96386a2a4eb60cf5d490472e73fd62ca8bb0e78d4f9f125 SHA512 177fddb001e14281510e34070f88f8e5167278a46f1d93d9286d9606b7673346f504e4064d7ad53558e6988a400c728e33b663ab398fee12ae23fba7158da5fb +DIST regex-1.10.6.crate 253894 BLAKE2B 176cf6a1e86aa8a5004af5ab0d6cd4178135bdae3caeb6a8276b8739858c65e9ebcf23749398a5a91adcfee9cca3667b306c4adb6307acfe61dadba8c6f3eee4 SHA512 ec28961d226c944321d9953c42e43cf2d23b8ca0d72d6412e7b0f572c407aceb079bb82502d124af94d71d67c9e5e0c9f66ab9f31edf6023ff045ec37b770964 +DIST regex-automata-0.1.10.crate 114533 BLAKE2B 0e357229f6825f14339b1d7c40730b83e62bba12115d01ed20313320766e769a653a2fcd2c9d19af51a82c38e9e42c1a31d005e1f44f5b6fbb3ead7c9c74027f SHA512 56d64da361afce82c6cb49e70b99ce1fca3e1969c54bba5f9971db135f8544c65f49feb8827789947b3d1dcefc9c49a7a434a7ffe0d09c5900345a1733723c5f +DIST regex-automata-0.4.5.crate 617406 BLAKE2B 21826731ed5439a12cdda5a1ef217dc3239a0884d038170855985bf830f2782bdf4dbfd1b1a8812812db3a2399dadf8c173e75db635dfabc97382fda0561bba3 SHA512 0e9681d5c4529d49ff2555b7b73cf234b1f321a7fc634beccdf76c2bce5094e8501403e8caee2b3a16ac299cbe4701d891f1efa380b54f9dc2d92bbacd4de611 +DIST regex-automata-0.4.7.crate 617582 BLAKE2B 6295d866706b623b2025fdc0c407086fec15053229d708713d0ec165bd526ba25e7468d0009625cbbbc21d20345f0af2eea10addf6de633e8e6a02dddced67b8 SHA512 b19d00d64bb8cd833cfb35fabb162b9481716f4b7f6035c1c8f1de4e0f90e00823d006e057aa3505aeda48c9e1802e61173c4a2878891129a3a918727e43b0d3 +DIST regex-syntax-0.6.29.crate 299752 BLAKE2B 2408ebfe5f0dd6578c33f18e8ea9a0a7a84388420c5b67adcaedde477f3f67fb3e39ba9fab1f6892c7ae7fff754c4aca51314601529cabc6a8fc43af38a11f88 SHA512 28a58950d15df1f0ac4ff4185c05b535e8f5bf0b75f79fad24e40e17a02570d1c9bd9cfc919eed8756a1069bc489c5fdccfd04f6b8266c83e3412b7b4bdc262e +DIST regex-syntax-0.8.2.crate 347228 BLAKE2B 211fd1c35ad0f28874d4b4d276e0fb0a27e5a1608f2f16ba2333641b154624e378419daf8d1c955f21ff5f40f6d49c89569b7e11ea5649850846d0fe447a675c SHA512 301dde555f300298f2594490ccd8b92033e4917fe9b8671b8a97db6c827793c73969be85a92999964dcaf3177edda51abeb576811ad6cab9772964dc0a77e728 +DIST regex-syntax-0.8.4.crate 347577 BLAKE2B 400323cdad2a7daa8d4006e4dd7a7b1234704df0f80ca0f4bb19447f8f1d270053bc8aa613e48291ab3a78c7eb02d7afec57bfc8d966a48b372a4c80de9b120c SHA512 10719c138d9aa304106fcbf77da0b01645d1b6fbc621abb639dbd43ed5fc3dbd22aaad8b86df55a60e7b2b4fc347b6f41419131d7b047273e146073250d892ed +DIST relative-path-1.9.2.crate 22420 BLAKE2B e2fdcef72f1633b2c315e5d2d316d56defe758fa916e872d84a8450ca0223f54489541175940beb43347c3a1759e4ca4d4afbd49410859cfeb6bfc703bc7a8ae SHA512 fa12c9df710fa3b5f9df9ada9efb13cd52cc10b151cdba5ed094fe74c6102cc557a5f38d05c9c0fddf2510aa13604428aecb4ee9b84405d02a98e6ba3177b2be +DIST relative-path-1.9.3.crate 22400 BLAKE2B c6bd04b060013de042079a741a864150632c02cdc493ca1cfd746bcc12f6ad903f8f0748ec68261c979d833089c0fc091f7c9da2b2936e8f75dad8d4638a7b10 SHA512 fd5c88d370865870570859a110245e009eba557225e4297783a606227b13b42abf0c7e69a4beb5093a5a9dabac1545afd988f4c831abe912c21ccd8013c30382 +DIST rfc2047-decoder-0.2.2.crate 12045 BLAKE2B c6b43d386cacfec23859ac04f276348efed831028f0454668c5701f79c8f0d6af43b529a9054138ba609a76181bf96583781653b6220e59a1d33e707b8972e93 SHA512 e81b276a7be47962a2591e7c39447d42b0ef52443f6473ccb18d8430b506f087358dca8fcf70daa2e9005d311a7d233e2dcadcf12799e9d6dd9e6da5d1dc559d +DIST rfc2047-decoder-1.0.5.crate 14393 BLAKE2B 530a3921f2c4ea59485e30665170c946da5869af50c4de5ca072980e98dc58e6e6a8077a037b99b91fe8bf8c21311cd8c0719a8b3aa22ceb4fddadc6292fd936 SHA512 9cb031b9edcd47ca5dd6154afc99a8050768f98fb915a540b2d3c1aca28894bec8e92044f335ebf1c2fd439cf9c384700037d76d21cc04b5d0a1ac3a3988fa7b +DIST ring-0.17.7.crate 4146482 BLAKE2B e08a879db4b3c8577bf20d79ba9dcc9a6dc906fa65005334be4f79b040200cda506ca5114aa0de12c309e483694f4a7ee9bf44efdeedbe12ac82edf4afdd91c9 SHA512 1b75cdcf51ebaa8684410e753e1766b88f95c27559baf88601db2cb267340fa03d7e4db38a2a91632993238be1913261cd116e0e8d8b541c3c8a6ca811d19b36 +DIST ring-0.17.8.crate 4188554 BLAKE2B f531b15cc5cf88f2ef00b1708473a7e98a42dbbd026027ef2c42f2d8bdba0eb1665621fc98db618252f6a131bd54b1493987a0285bf2b9a22eba4c9409ee1cab SHA512 e4966409a4078ee43bfc9cc659d08ad28419effe2a729c8c275361a7fe0620a3c727009bcfb1d0bab265af2bc107b50c19d868a4e80da7a8bb55f97e8b214358 +DIST rstest-0.18.2.crate 28868 BLAKE2B 44368c85da79308277d9cad96659520ecdddd767e55acc5a4f35e246af64a29112867c4ed40bded5dc0f9d3230d828f6ca98a73adbc1067b60a9119b3cbdf369 SHA512 b73b902c761717acf5848adf888c27e5c58fe304f235e91e1e543cdcfb4e678472b8fe9930cb559be525c0f1a037bdfb2d77b7a0632b021d51976b85288f459a +DIST rstest-0.21.0.crate 42620 BLAKE2B 0900551b119cfb9e18ea4beada1459b770ef263591a466a2247f27c443d8eb0d9dd508626b1144442f990a42995b0f980ccfd6175f2651fdbf18958ce7d2815f SHA512 baf52d34f47b9e400f35810dea724715cb66c494c44e08cf70c6372bd16d4826ef11e3e5bc8c56871c02d525595fe5198c7e4cfff8f2d1b355a2411d8996bafd +DIST rstest-0.22.0.crate 44425 BLAKE2B 1660650c95cfbe1a0bc5ff5f660481eccbd61cca3a1c36c169fbaac5b243da475af3dedd83c011bf679a8b63223a9f2bc9edb863dd8af14675ebb921f9b10dc0 SHA512 cf0509ba9e2aa638b1e56c75a29ed28bb4b208c19d625d0b4ce339292e1ae3d7dd9edcf7024abd0e0fc53284f936bb69521724099bb2a1c75c58289e2666ac13 +DIST rstest_macros-0.18.2.crate 57534 BLAKE2B d06bb6453eefa572cd784e38ecf9361873a5f3ddd5dc4926728183bc303e28a304030d45304bb287019b42337d78f294d9ae350d4204fee027b68c264272d86a SHA512 614944fbd51de32b5e7ec1b485c12cd68ed9fae6ef296f9a9811de2495bc27887fa5ff8695c619255ac18da5af2b6ef8a557753d96b4c1ec3d711a9036bc7392 +DIST rstest_macros-0.21.0.crate 54797 BLAKE2B c627a310467fbe13b1a91fafe7d7e6011876f3f73bb53016650123dd75a54a0b9b762256f721ba62cf4535b23527074b11a48ae837e1513cf37ee689b8932377 SHA512 8b1ad5feeb4820e14f64af2d1db081ac98d227a0a9096206c32dbb32501b9a59e44cff0abac605fa6c4a670958477dc95c48796a0dd9c83557acf1e7c08dbd87 +DIST rstest_macros-0.22.0.crate 58923 BLAKE2B bb4c1d95eabdf3cf25ad455b9f7781c6254c896139bfd408584153ffa43fee35baf101a2c3db691f3a1f0023e6fe4fcac40bc215d070250ff2a9b3137aae3ec2 SHA512 57d96487c8a230e681bad99c1ca379a41119828daee8807b1ad87a90520a4beb3ba319019f0680af577bb07e46f1a30b00e013be7c407e4071667ab33f050080 +DIST rustc_version-0.4.0.crate 12175 BLAKE2B 6fda2ce03eab45d7193fa0d70175cc7ffb56b7be85fb1314092bdcfd3948ea145420569ace3a47218a4a2a6e44a818862cea6dd8cfb945475496f63b591c29da SHA512 f66da7c6efe431db06cd01180d84ba67fcd38f8cd6ef693762957c00ccc2211f23c08079d7f184776e08f28d2d6ca3bdb5f5016f7de245c6193d4722891ba1db +DIST rustc_version-0.4.1.crate 12245 BLAKE2B 0ed627c560d88e5ade830cc5f72c62f6ba88be3e30d0f8db34761fcd0b284e5b2fc063c240149aabdfb12c8410ecdbe50cb10a3544500b5a020f95a31cd6709c SHA512 7aa8a487ca7411b6d23cae62f7568fa3474a7b1fd1589621071be3428a550ed3b7c4ad68277a8f86849e5900397d7d0e9d678f5d423742a045dc7c660fa6c598 +DIST rustflags-0.1.6.crate 16805 BLAKE2B 2aedada5c0fad93186ad513c526d8cc738daebe1b486a7abca89f0f799139e16f683160005c7f9d692a1576f30c349a70bba250a51b9c14c0310ae2e1b902744 SHA512 6de4bf2d442d7a536ae061232daab3c2f4fc85da1349ddba16d51e030e0714ad027e70200a3ee0356e8b1e7344ed5167896e4aff0e703d63932aa8ec00aadb6d +DIST rustix-0.38.21.crate 358962 BLAKE2B b3e4915385aaa1783e0024caee2c454d9ce66542ffdb9ab0f0ef02f07b6d583a49b29b25a604832903f7909a0362bcd2260958cfe3fe045af4df2ea5c62c1da8 SHA512 f3b147706e1befb9d743bb57c7f8dc0a1ca8f244ed98069dfc757ee9d7281f097531bf7d1028d21ac798ee27bfb07b2ea6ac395dd0bc6caef4647fac88669833 +DIST rustix-0.38.32.crate 376999 BLAKE2B 681ea50f5405b3a749a26a481995d3a85800378067734bb857e32e5d3764687b0da4b3749d227174440e432b374ae9ada154a8288e4353ca2ff1b851698477f4 SHA512 8f028b4df785aa78fc798f3e053d0a4fb9b3c552a47f66f52f1666f4c1324441be6581ed643c4ef0f56d92e1a078c6d3b45be183fc3df0ed1fc89de0d610cad6 +DIST rustix-0.38.34.crate 365160 BLAKE2B 02513c2513ac45897b659f0d332a0dc32401d238b8fb64ad4a90ecc4d8952fb042c0bde4bf13d52630cef34e73e96dd32cf772a8601b4f6eb5e2961f0a394add SHA512 717cf26e2ec792b41819ff964888adb265a215d2b6c6e2b7a8ca1f7f793b713b853bba9cf03c2cc88b0f9a5eb1a0478faedbc05526f39bd81583e7b1f764756f +DIST rustls-0.22.4.crate 333681 BLAKE2B 01f84b7f44883c807d8651b6058647180d6e9d48deb51fab0e76d7b587ad11face13215170db3bb7d0216505eb108438dcc3bc08ed2080816401f3955f73fbab SHA512 0b62c741b73dd49dd9d5531c9ae749fc8eedd4a396c5b4c02b1b33062d56c84e327e12f5a984b9ca22c7984103896d4ac69899032397dd6eac1b737e0647e2da +DIST rustls-pemfile-2.1.0.crate 24757 BLAKE2B f356e6b29ae360ad55a7d70e78d053982762f190b88fd569cf2d0e9481537ecaf01afd5a1c40a3a840eb0e2a49fca8665c68eb931229afcb39430d7096210b16 SHA512 0a4ba2f275b715bcb13f9afe7c24aba58b8f283cc7fb683c1c338c02eee3aa80aaf0c8133d6f469b1aa2c8c48e0ff616fa4bd1e6d527f99ad984f2facd38fd30 +DIST rustls-pemfile-2.1.2.crate 25928 BLAKE2B 790545dd6347badda8f67bbe67b8d4d7de9f24c134857840d7ba2335f2755cf03c05b26c16c8b1e397b3257cd39a6d3a333103c2c3ea32ccf4118bc3d42995c2 SHA512 35127c68250c31f2fd6924355ec37d5318d8a86ad38da48e68b3ea6e241deeb019eb967c510e95230be6d6c3357b0a85aa022942d21a50423632f8e2496177cb +DIST rustls-pemfile-2.1.3.crate 26757 BLAKE2B 421c0e829d28d94fed3356195ad0628f7f79cf8c25a56a5699df6c385d437dbfff2abf6bbf8b63af28658819f225d2728805ea0c7111e572fb2bff0523d31e42 SHA512 94b98d05783ed0920c9ef89259e740ca77f8fecb4ce4ee894b7ba30acb0fe82f41cb2681b5eddedf8e3ba7c68d1dd740132a39028a99ce2e1070d7d88d99d641 +DIST rustls-pki-types-1.3.1.crate 21637 BLAKE2B 7734df5facdf21120d0dba9d6e2c0e30ac36d4368048e89639d53e68d6cb72a03cab08dc64e443f6d5b43c3f25020016bb2010ec8d20c329fb60d6cd93c9134b SHA512 741cf0def113336865320aecde54a56cd5bbc7f3aad6e71dd209b4e38b642f42d0244b6fabf03a55467aa42fc3d1582bfa1fd5fda6402ae2ca11191f21158939 +DIST rustls-pki-types-1.7.0.crate 29555 BLAKE2B 9da5d853671e2e33f46434509e7c83edf487a6a940e1bc8937c3ed7900cac590674bf2c5a5edac6055a2bdf763b132d4624a8c51caf0250d5055ce5e8f4bc5eb SHA512 5502795aebd7058084d0e30d6c09befc4182493113207f539a8d42006d4189158e9028245aa627d6943a88514b6292fbd56b5ea1abef8c83a429bf6d641f6f11 +DIST rustls-webpki-0.102.1.crate 196873 BLAKE2B bc0c573369bfca4ddbf3a8f8cd7f62cad3e4f9bd225a4221355697e82f913b11078417167575204523068da1e1b3543e028969d524851dfea31c0a1da8576d0e SHA512 cee1d6b0251bbc554607415142d1cac78e978b6005d375394e8cb09016cf6f14da5e08fca1a8f19f0add505a1129ef81f37ba14f86eb1ff78823290873a9423e +DIST rustls-webpki-0.102.4.crate 200657 BLAKE2B 7d6c27ee182e5b92fef74504d9331c476861b1ef6f67df44b31382d3bebe3c2c1ed666fa535b2a213ad602449fdd23d0ad1a7b89332efeb950686ab6065278a7 SHA512 f5fd01401b74ce3bd3fee6228fa01c29f0ad005eff0314ec19ca9cafe401b056270545b239050cbd72fd22b64a5376bb1d1c3cc5e29303c7d502d5983513d8f6 +DIST rustversion-1.0.14.crate 17261 BLAKE2B db30d01914059a893bdb4c448ed0bf04852085c2d948bfbed8819a1d2317c34133cf609abdd806ad628b86974a9c1ab9d09f79743cb8e13257ef32cd444f49c6 SHA512 466d753c28c4899ab3da3e9f3366f7ecc435d484f51e0c07acfa5f3367af0de27ea3bc75efda22159b4990c976b1466a27e7c31c834c72a87d8234318357454b +DIST rustversion-1.0.17.crate 17621 BLAKE2B 1f077ca6fd90333724d1ea9df7f5b178f37f895b71a7b2814e9ba8618bffcd2307f9cb4ac2eea25d461a6686a4b5b51eebb80f1b1ccc773d4da1948c47fe8abe SHA512 0565cddecaedae17e7cd99bc34f54cda242d4c29cd4269f8e3b178ff91d49f3682e7ffe66e436bbb138299736c8e55cc143fefb74c076911fefcc41ba98064f3 +DIST ryu-1.0.15.crate 46906 BLAKE2B 6d6949e43aaa27fba0ec6002fa11ba859af8d867f87c90d88413267186abbf6302b817985bca3d577ab3fab2e319e11756f144473a16330dfd8fc7b604cdc4b3 SHA512 4655b5647f919082a9b84b889539ae7fb23a1201057cf280efe79c58cb5f040864efb7812cda5021bf6d34838a15d173ac8bdb0fb9fa2dba85173d3efa5a826b +DIST ryu-1.0.16.crate 47351 BLAKE2B 13c72ec8aa608f6c53cf27c95d06b90839c5bec5e54b0441e9c4f779af3dece30d01a2276c717a733f92406a5a02b09c045b2b5f92714fe492d7263b6c6808e6 SHA512 89e3e18346ae6e4035787766f286a6eb62f5294e39ad902cc29e95c53781c4e5dd629f567f22ecc7e9fe9d1c273323da9b867aadc9cd8a066727c58330b51b10 +DIST ryu-1.0.18.crate 47713 BLAKE2B 409cdf4b4e77685394018371e91ad6fdb175ac57e1df9f902871f13208515e5a2ab1daa226fc1e7291278e64448332845be4cc9409bce3b2f3daed409259e104 SHA512 a9b2beac778ec47e6be303148d7512ee681bd2361f6e4ac6db32c8b4baf86a8c5eb5b0d02eacd6131ae88c7b5105c57018c3050676e0b3dd1ed9c4d2fd650e84 +DIST same-file-1.0.6.crate 10183 BLAKE2B a320c8343e0b38078ba81c4f0159d886bf47764c74efe0d7cd2b3218426e8341b51e523c00a9e5fbc2ee1057618296bd70b576c68751bd55d6ddb352defaca15 SHA512 3ba35309742c8db63210d9ea78bff4ecd80471d69e6238eb96c7bf0673814f221e2d838fe6311bfc5a0e71b4a7ccba33e07859c0b9cff2171969ff08a4214a7c +DIST schannel-0.1.23.crate 41667 BLAKE2B 3f34ecf4cc519f5302f0ab5207907a275c68e6fcbb47630aec4ed5d5f1a1cc7475f6d7a8c22361e9878002f9f54314c1f630ab0c1f77ea309714bdb7ada6c9af SHA512 dfce25e3b8bc09d8dd1fce2783fe02ec83f74697cb24aa212ef9369a628685ba488f821cb3e5f863798e0e59995038c8d748f74b89f7929eb8cfd804d5066b84 +DIST schemars-0.8.16.crate 57072 BLAKE2B 50d4e73d6993b72dcadbb60764cd5e2c663f48aaab5b246d13ae5b5f04eab8ad279ff6d09a77caf8137e7aef746154fb21f44ad195f2148ba4befdf057907a41 SHA512 738022b563bedfc73f2f2899216b8ae4cf0f563c1a6ac91639715d5f36446d7011fadd5554b8a4e9e569dddff836cc136ea2be5e65b72f85613a4a890d355a06 +DIST schemars-0.8.21.crate 58475 BLAKE2B dc3e96140728a9aa2a4ec5a4a46e12f016635d818dbd78865dc0281b6f0fc05174fe7dc0ddf085f0ed5fe26d4a4e6b1bfecd6909236cfcd83c9471b876d2d01a SHA512 23a794ec52d83ce045c8b2d633913b3b29e4cfc9d0a29f76aca8cd5b31a9c707ffc04c94390ab719b3c8109f37c11a00dae73ec1719087dfe7b3c4007beb066d +DIST schemars_derive-0.8.16.crate 19064 BLAKE2B 619e94920b9188b683f576285ba718559a517377801fe7b09aee9c1db188de082331c7da8de34adef547a1cd90f46cff2d1f9dc02d8733a26373fb7cfe5e7dbc SHA512 000554c30ea0b8d50752244204d3eeaa76f8b96c9e22f3a40df840cb68308dc94ac072c52fbc8cf25658af88011a69a5fc1b9ebe910c20253a8f5a1162601f46 +DIST schemars_derive-0.8.21.crate 18703 BLAKE2B 62cca4add2d8282e0461d52026a3d7b58cf6a8b34819179336648300b8618056c6a1eba49b6bbac098a101d73ddf577bf9e6e8afab225ba67cf519126c6f9d06 SHA512 2e24af9e86aa1c04921608a7ff8a62ac1c3e7971591db9c8488b6e701f289fe56931ad208bd73f2542fc1d95863fdda2cef9561585b7e760eb99e187661ee102 +DIST scopeguard-1.1.0.crate 11470 BLAKE2B f774eb90b7d3ffb2efba47518e9d1dead4017ab4b38a4bd74914daa84a5af4bf9eb63da0496e3924499d79cd0439c37447aeda4a21226f95645bddcd6becfabe SHA512 368fa5726df8f42b599993681579a9ffd0196480ee3cd0f9f671e8493f3bedd1e1779bdf2beb329e77e0005fa09b816e3385f309490c0f2781568db275d4d17d +DIST scopeguard-1.2.0.crate 11619 BLAKE2B 8b7e9ed6cefef9ee55407fb9690d57a2a98bb93e5105aeebdb475a52485e9e185255249e1dce8f83cd80534e7402d485aac3efa7e8493b13135de27550cd4bc4 SHA512 6247719a15fe1e4e2d179127b9a934bd2f99367724f41175ed9522f58824b6bc69b35002eae66b35880375ff61d77ac43ddaa78cbde7160a35183a1da32d3fbb +DIST scroll-0.12.0.crate 24145 BLAKE2B 93f070ad4d0656b6cbbbca78d27269e8fd5895c515bcfd51152bf5ce2756d43ff0bf13dd63201f4f1207feb993bfa853c9567a298a040369dc6be91324570deb SHA512 475a9b3f09d4164a7192c9d2fbc209354b9442e669c3cb318bd3f31d1a407aa328543bfe315c12ddd962bf8518ac378476d6b5677ecea170e6d507c70c4ca935 +DIST scroll_derive-0.12.0.crate 4693 BLAKE2B 957aa96820cf40ea49562dbc12a419c7b8b06bd94a759aa5494f4ea4fa08a5f154a7dba8acc3d8bd41c1a2f259bfdd2d3f4b4dfd3dabfc30fffa021b4aee4930 SHA512 db2ede0f6d16783915f5f155174fc0cb700cd054a0ec54fddeb899f74da4dc2ad5acd6f0784701f93a95a42cb04c82e7a7de9680ba0fdaf4dbc51a2358610bc2 +DIST security-framework-2.11.0.crate 80191 BLAKE2B 23515556ff935e7a19f282f7dcdb28bcc93ff1b14fae069d1e1be35abd5651a38c7c71594eae085c8385e48b25fb84b6f5fbc44636b5d1badb15e89ec6acfcbc SHA512 7a1a1d1b807cfcc0c87b27a13aa0007d5c29560a45f20963cc84fc705385554b969b4062c7f8b15fe793291ab624fb2a5257c05d140c53200c2eb344547652be +DIST security-framework-2.9.2.crate 79295 BLAKE2B 96be139f2d2b9bc2fec7805c9e90f19f68fb6cf3f09a879f1d5952b502951900fd6889451c6866e53394859a0f8a842b4a674c4bfa82cd71f48195c0af365475 SHA512 fdc58c1c12ff849af3acf34208411caee50f30b9d55e20ef9d3922ee37664c606abcf90c4b415e5c22498dff2116fe2b2f374a0bd382c837ae7d281cd1a0a54a +DIST security-framework-sys-2.11.0.crate 18718 BLAKE2B 4fd8e8eabdc910f656cbed6d6f941992eebc2ebe29c1d85e4ee2de5aee2e4840f2952ffa0b0f9ae88329a2b16d66c3575796f476b873c6bb3c3efcc8d119ab6f SHA512 e3848a45391ebd98026ecafb0777852aa826b465613ef184cc33cdbaa75fb91053d46d417dfda6398339abd3b67788a567562e99b3c509b676b7ee5a4372acd8 +DIST security-framework-sys-2.9.1.crate 18284 BLAKE2B f1484b6b691f3616192ab363c81eb3d6279ad0bae6bb7fbc4eadfd9fc6b6bcd5ce42fb8edab1eb8934f40a1d42714eeb8ca3616871e8f80c90318834901e8ca6 SHA512 3118d1e982d94c5fc6e8ad6270ba398da98a042c7a2060eafb3b78a54491091c46529bec30d4f871744431f01b828ba2a795f695cd20d008441839f3c4350462 +DIST semver-1.0.18.crate 29703 BLAKE2B b1867f552ac87968d895c5e49123bcce0f8aa0ad384e421e5ac88bd04ae203ed6b731d5c77fb8488ec6601f1f02a8f2a207a9d21f1cc66d433032628f5d7beda SHA512 698dcd37b354cfd6ee452dce02d16051f23088ce53f0b4d099e1e4ad0f9350996f0b9b2e1c3ac7d5ed258accd92773266892e945fcae28055d4671c7ae5aac02 +DIST semver-1.0.22.crate 30446 BLAKE2B b77a951d959a3685b0373c80b9991a8567f8926d093b23b7b8fab48595b5d565acf7408fbfc8f4d58331f39e316a8068885d28bcd70c1476d1cda436a2dd88b2 SHA512 7dcf9b6a02650d71d6c9ab3c29e44fdef95af296208f26aa7be6fd6e16773e5e5e66418c303a0589d1165df6dbfd46ad6ebf9eb5b3adab25a51f340947b2d949 +DIST semver-1.0.23.crate 30622 BLAKE2B af5f7401daa2004ac1fc419ff907a65feb9b11743ad0feca0929bf2409eb81e03637ec5f92ba9f38ea386c4ee5cde72bd3d2042083e2fb0d6fa0b839b1c5093a SHA512 5ea1fa17c08d1280c3a4bc8d28494e88ee05acd5dc969ef6f0c6f91fd3b5a8fbe999c9e8bbd2da383413038b8d29fabf02b87bd5265bbb8333f3fcbe409103ec +DIST serde-1.0.182.crate 77171 BLAKE2B 54e3f0bb182cb1d9389d176ce504d6a2720b3868df0bd810e9eb1e730efe47c0f2035fd0b5c021da2d476d005206e3a44be1813477516c872844ecc00752cb89 SHA512 94a0f0e2eab1820d398647f79ce060d23112ff256722d395252d4225c5bd7bcccd79f944e761241df4e862c44ff94ffc3cfab160733f301545e4ea2cae7fd967 +DIST serde-1.0.183.crate 77210 BLAKE2B 280e3d253a29b664b4e2d17f41397b17fe22af64417facca42d6ca0c839f1def745380a5402d7a87345bb16f4fdacf9a8c01966579b8c08fb06c05f097a87e68 SHA512 3a27efdff92cb1f6b50449a761efde781af91584b8410fbf5ce37b20005e7d46dc4c750fd1730e15468ea22aac7799421c4e60c74243c65ef7916d3cbadd0ef8 +DIST serde-1.0.197.crate 77087 BLAKE2B 4a4e04ededf5fefaabfcc4e17457db823239e8eeee7631a905ed47800ca10d26a93632e3a9d1b784b83f84168d0d649cfa2e6f5f1e68ab15a68e837cd5b6c699 SHA512 69e42825fce6a0a5d109979785daceacfd6afc5641e202fe83da32e2b1f968416557cce97fa014839e873e65f85c27494c8f8e20e6e9e4fbedf20d0291880410 +DIST serde-1.0.203.crate 77935 BLAKE2B 3d3dd4f81f7d74b60483d6759879a9f87c0c7d615aec308bad1bc575fac4e2071dc86551c2789e87331dbf8089e923ae56fff82e6f5a9992cf850121b052ce1d SHA512 a8d302589244e41f6f675e8d199b2532b29f62b63e45aee141a93dad96033e4bbb27ed01c11e329ec2266cdcc6f2a40f41dfc7d1b9bada69aea81d35d2d82cec +DIST serde-1.0.204.crate 78253 BLAKE2B 6fdebf3cbcc0327b404caaae43c87ba2b6105374a5ee3eaa34d44866e782132cff535da4c069c007783b7b6468d55cb1ceb6a41da74b9eab03ace7cf4811e09e SHA512 2fefbeed0117bd791fd25dd5ad0c99ed4f60aac5919605b6f642050f748dd472bf9d4d121b78b0cfe8719db30a675559d097bcc7542cb57451d1779dfd8d294f +DIST serde-1.0.209.crate 78364 BLAKE2B f6b4c2bd931a8067482ca033211c4e85c0dfd6084cb599c38a9ba666cce30489685a3a6a8a539eb6e41141a52328943dccbfe25dbd857af16665094fdf7c3f45 SHA512 25d2236eedc08fa3b9d078a1971df705c4f428b7a4e6a2d28d9f0f9893c19de745bffffe3fa9f3c08074bf4359aaf09cc28770e4b14c21c66d6a0b9411738f7b +DIST serde-1.0.210.crate 78338 BLAKE2B b3621d1313312177a346313e6e384fe9660f74eefb18e6cffa39fc2aadc0ab73be84b9037c59b716e5feafcd73f4f054f83e6d17d82746984b3064bf8d3ed338 SHA512 0d853ca51543ae8b4a0c70204ff4e559a4eec77af3d3bdcfc75c5905c80d4ffd1bd9eb8258ea4f6ecfbdd26477ecac7dd698d84d86759fa32e03a9cce02fa4ae +DIST serde_derive-1.0.182.crate 376750 BLAKE2B 56bff75add8bdcdc7d887eab1d4b0d7d8016a8e6069850e11b07319590aa42bc2fbd57ce69fc4866d62c56768ba236a0642dcae24efa67e2e67be8f9bb2161f5 SHA512 c523b31d92597dc2d80ff0efe491f78fc45663db1f5a86769f8e4d90738ee67c1d7a0f09ae8bd0a9cac2c59c88fe4373bb5e5285ed7227ed983a47aa0f0e6552 +DIST serde_derive-1.0.183.crate 377265 BLAKE2B 041dff0dd5822b3be992cc65c8d789c86f8dda3a42ac77dc1a6c44cad4412c8c9fbb02f7572cc1ec4e4ca731d5f57a765d30f9357827ecf8210ae7f54c26d8f7 SHA512 c19cd2c9665b88b70a12b972c5b30d9ac6c604c77578bda5d7c6c5dbe01f097c1d6d165f1d73c204768427042b7521f43e40ee295c173e685c9ab1b4c23c8fcb +DIST serde_derive-1.0.197.crate 55771 BLAKE2B 73708908b6d1e104af4c63b498bd25c5a728e07e22afdf92f15754c0f17636efe44c0560c1f0df1b9a30708e8e8894a62f1ea57c234b6dd861cb9c8dc044eb4b SHA512 669376e248b76a5ee8b9c93fd9fe6d35372e7267fbabc14730539ef28a94e405ee5e9c2cc2846897d59d6153742cdc6799f9e2c87f20b9dad119bd3a86c28994 +DIST serde_derive-1.0.203.crate 55867 BLAKE2B 1bc8aa96328bb83e4e4ff527b1df855bbcefd333f0c43c96d1e0b93f98a46273dd88a21653bccc8f517c4fc06d17b9b44332a963d024796e0a2c18a5bfecc824 SHA512 b2aeeab33395ac11ebdbd922fcdbda29f2592e7a20e78aef250713baf269cacf497271be7aa407f657aba33da132df0e035be046fef070f915f234097d1dd392 +DIST serde_derive-1.0.204.crate 55871 BLAKE2B 8f0cdb244a820712d557a3273e505c4461f4d7db89e8394040b4c66ede787b6b38b4c9923b38959ab4042c9076b8af72008c0dd15ac93a0ecdeb99da8fb526ae SHA512 bbb2b5e60e2af5bc7528b937ffaf0d3ffd433dbd9cb2592c1e07090620309057e4f11cbd6112fc1d2c5557e1bb3c0f4d59eb06ff06fa021ec683ab880997140e +DIST serde_derive-1.0.209.crate 56023 BLAKE2B 752bc9f46b880d0ed8a4f7e29ffde1343c63c4be1e9740afb1a28dcbff5bedfe077eb51c7052adecfbdbd9942c30b63a27914deb6401a2ecaf70fef0f64cd80a SHA512 22c4eb76412bd73814d0b86209b110b9e59626f64b41cbc250755144e545ff30fa69972ac93d74f988a3a6a239d9138f4e8a23b283c746a0aa5fcddfbe077cd6 +DIST serde_derive-1.0.210.crate 56020 BLAKE2B b346e574c99b6a8b12dfc29b20a4fd2daf8abfabd3714ccfde059a3a1f14a5628d4acf6a03f8076174fd28adfdb7cb9bbdb8ac0d4403aa2f43e917eed4b08028 SHA512 1c54d70a55007c00d3ff3d8c2096f4f9966431ba7bfd9195bcf41932de71b71c4ab934f9a8c5067cb56a042742cf0efab07377dbabf12feb1af6d20399de00b5 +DIST serde_derive_internals-0.26.0.crate 25382 BLAKE2B 7829d9f7efe64b057efea96d60e4a53623757a58fe7fdd53c1225c0a1f1c80338aec9e2a8c4033a1e90f9e18940796601a2ef62f9a423fc39adc00a8b9b6e065 SHA512 acf635d10b41400e2c10d326fc7ca60dbe9094c2d1d94f4f34905e6978b155e014aebe29e0cc2b00587c97751360ab0dfa71b5c6901629bda9322754e2f07890 +DIST serde_derive_internals-0.29.1.crate 26189 BLAKE2B 09d2fd10c73ab114efe244749678c166afcc3e6217f2a4c08c01a44e546471c5f7cbb7e79ef908fb306975852fe1ae32b7988e04df3741ca82db1e3a3d6979f8 SHA512 ee7c8a35094b8ee1d8958f4aa177e5c536c6c7706d446e875f1ae1b5249738ecee053a0239e1508114b747797fcd080ee33ed88929ff1f4903988f64f038b771 +DIST serde_json-1.0.104.crate 146130 BLAKE2B 62a613eba9c39bc3f007404995528ac101df3e74d90049e9aca699029f55ce4cee54a1bbfdd9e69cda9ab3e7ba9893fc66f3f9bbbc1eb358d570dd292ae77216 SHA512 06b2f3c818fa5819ff936d2f456fccded743ccc336359bfd1371aecebae9ca2d4f77879f61d1cda510b7a1aaa47b0010688b8e8c656388950e79fa5d007c7f6f +DIST serde_json-1.0.114.crate 146986 BLAKE2B 229f0a8e2c0bc35435b49774fab9d4cec4e2323e85e2f97ccaa2a18277ecfb9cff9e9b165786e782cba043e9ac670717364b0f9c145254eefd74582b728f2186 SHA512 2c35cd0e29ee2af6046ce849b5854b82b90f402b51c04ea86b32ce7d67869736f17a4d028dd8245c31201036bcca7a1d3df11d842a92a45b0eaebd809687d436 +DIST serde_json-1.0.118.crate 146962 BLAKE2B b85f17cbef0cb9fcc8af5d8d18a74850804de631f8ac94193bdb0ff8c95d4c8507876e4802005e0bc8fc4745d52c79be153d825e106090b680b620acc5b1add4 SHA512 1fa7e01d849684e3ed6f9bd67ba9862f822dcecdcb9110a43182367225f559416f855d59f2b8bd943756957932710b930244963a1f47a3d7d530be19dd412f20 +DIST serde_json-1.0.120.crate 147062 BLAKE2B 54f93ef2b0f1c9e7c5a8e8797fd298c96513913a20c3e08a21aea39a15ffb5ad0269d5daab10fceea7164ba432e355b89d89dea2985f86bd0e73ac3920f827c5 SHA512 dab44850326f9020d6f6dd3fc8147e22eed693527fe9cac2c6bc8f6a030f461061e8e54d2780382ce32cced63b5a016372a4f9938effdd1631d8f3dc96014e3e +DIST serde_json-1.0.127.crate 149465 BLAKE2B da5048f70a0b7594be0112efbfccf8d6575a77b324d59321cbd34d355978aadb2ceea1bbcb182412547587235f58873ddd2232822f020e2db85c1599cb0bca8b SHA512 f14f5eeebe07261daded47c3cbb6d511da4633bfcc46ea1b0600063730dd4211a0c310959e4f8731a688d18d60a46f6dc1c1a1f052f170b6207877b93742a88b +DIST serde_json-1.0.128.crate 149520 BLAKE2B 246eb865f64a0f161b79f3d4f783dbadbc930c4a19edb6c0fe8f0c6145c7c47be4b692d3e084b1b500820ece8e94214820978cf898926dd805bd431fb411bbc9 SHA512 9e6290d3a6a971b3c37bbc97097b8179e64c655779b43c7b75303a35ef7030f5401b3a5f62cbc95a7bd5f42ecbefb0b469234d78a76c8c1597726d8e08908a7d +DIST serde_spanned-0.6.5.crate 8349 BLAKE2B f4f8f798ae3a02c0d5178aa12a94bd1bc08fef88b6a81d782ba07ba36fb0d89927ecf621087faf376b6e53de12f6a96e0880ce0cd01ecc31c5dab7dadc6f3ff4 SHA512 bffe2398629ae5a5a5bb6d5fc2fa0f4b94d02c96e25d1be2fb9ad95d8ca2fa9bfdeb3af11049ee9c050e497f3beca108f03020f88f6de29b208063c3898af354 +DIST serde_spanned-0.6.6.crate 9120 BLAKE2B 6748b04f30cc63297fe01cacdef743b688aa0777b600d603919d05676913133450c97a179c6cbd4a62534431b74c4bcf63a60c1185ba89cd8266411d3824aff9 SHA512 e07254723645c80d10c1ab9a7282251fcafa0b5144991568b1b1f85e7c8c8bbd82b5992f2ed73fc7a988f6a0175fd79fc927c6b28b7420e83269c3364d7ead4f +DIST sha2-0.10.8.crate 26357 BLAKE2B 1d01b381223a931dc631ad3a1191f5378b1d2f3f9f20474c5f020e366624c73b08330ce8dc4bdd3e63b15f647276f533de655b545b77f70fbedc1a1846f44f0a SHA512 3be73133a6b7690e14acaead47914dc92395dca4191fb657a2ea186fefd0ccd94d12a1121d63a26027d9a9c62b775c53202473edc461587b9dcd75472af77785 +DIST sharded-slab-0.1.7.crate 58227 BLAKE2B 9b4c4e4849ed324cf48c2b905f21139d1d65aa5ab13e7fb11817cac9a32ad09f8dbb1e50a93d40cafa0aba872792bc92f7bd2e219f62f80695409e949c07978b SHA512 3be7438d4a75debb14463477f34de6db1ac38abe958ada5d5dae7ae8d5993e245da69fcb989d91aaaffda5f2b085d4bcc88d10e07ec567b7f40a21437de6d4cb +DIST shell-words-1.1.0.crate 9871 BLAKE2B 7923b36f0ba50c17ac4eebfdda34566b615291253b7b41879b3f64b3fc1325e63948d3d44801e40748b11ddd2ab201b81d238af2a2007c7a57d71f5dcd0667f6 SHA512 05c280a8e1f65b205746560a82e397689a3b5ec934219b558ece3a25efbfdefe903f9172319240e96039b38fb2c4be6e070805aedbdfd10344d9144b9c93de00 +DIST shlex-1.3.0.crate 18713 BLAKE2B 18800c364d3a628f1a3125097ea82fe6286550c2997235df0bf8483a3906aacabc81308cb239887d46ba2f457cc6f8acd5aca78316707eea5098cd5666aea67d SHA512 5c8cedbe666a14b8a0874defb9208146ce64579cde52ed483e4a794cac5dde6a24bf8d684404edff582f842e1fd4fa3fbeddbe074f191e4ec4aa517aa456fe8a +DIST similar-2.4.0.crate 53147 BLAKE2B b30771e3c26300f9ad691566af22faf4592225de44dd55abb1231aa3641a32ca71c83fe9253dfcfb0c438b6f599c77358595fa03125d5f343cc617e99354dfbf SHA512 6c8f1cb194c165ff6ad64298d37deb6bab0abdd51921e29395e1c86268c65db1b4a67ac03ba37dbc69a0ea35c0f3770e894de7253f0e410be7bfc7845a45ce7a +DIST similar-2.5.0.crate 51648 BLAKE2B 43515b3014ff75e2a94debb0e40a081d60dfa371bc3bc3b3a7944cfbf2e326a8a56c6aa26ca2b6f9ab6f32929a89da673ec2fd4f037c07f8ff91ca95a77b1fe1 SHA512 7206380b6e4eb496b1dddc4501ac03d716bd6b5228971a35ca71f507940e799410dffad7e50e52c6f8fcd43c570ecef23220962fb057100665343498a5ce118f +DIST siphasher-0.3.10.crate 9889 BLAKE2B e5dd6d265340b4c9e4266ab1ff3a20f1fb87fd493b2d7b5fba32d26421cc858b38929e4ab96941d0c055375b8acebbd04236d994cadca324500ed05064b9bfc9 SHA512 f90425a2cccc9575d377bb92a765d34653ddef1ac12b7c63dc6d700aaa74b525787e11609061c2d3e44ea56fe0e4b8f93f7b13f0279b5de2e0f710c5caffd4ce +DIST siphasher-0.3.11.crate 10442 BLAKE2B 771221614bbd56f609b9743da4352dc7a2cbd0f6257952fab0cd052e5e5b258a4c95a0461d6d1b579dec90b72d66a0e58e036899b3db8341ae753a421a4cd4d5 SHA512 601121bd41da896142dc6ccc74a6eec3ebee3e976857ab8b5d21e915fdc8bc6e979af66a489c406371fbbbfc7a13338cc4b3744aa981206e43c53998f3e1699b +DIST slab-0.4.9.crate 17108 BLAKE2B 8e5288c4d00efa915e7be27b55f2204850968624f0d8101c091a357131106bceeea7a63c98007420c12f67893dd2228b15d3f23508108c3a0ceaa605474bc7a9 SHA512 b6b5423ae026472920f7c9a4abe0962314140a36dc562c0a9e3fa60725b2b8b7a8b343110d9d4c0e18fb318b0103e14c0ccbc9ae350d5563a5ac80c35f228c40 +DIST smallvec-1.10.0.crate 31564 BLAKE2B e3e46a0781d3a7892a739b001592d462d0704f010363984c439e3fe4f75aecb9720648aa1e9bcc56bb3be848dd40cee578212439f78f07a807c9441c3c3e0147 SHA512 a09110184582dcc01d7a0d3fa8f74c17bf726935126d3654667b8e9c4bc43ad16ccfd8fa94feae7d9b31913aa7ee030fe5936e4b44a36302b6ce5fe37372a7ae +DIST smallvec-1.11.0.crate 34680 BLAKE2B e54d56f6bbffbfa7ce5fe5f04e325b2e5cf19d290e4be278bc00a136e26284625b9c18c7c2b10b7fb8fad0ea7e3770f3cdbcfbaa913f5ac08d0a2f8b4e0de188 SHA512 41bfbecbc2c244497568a41724d65791ec3fd6d8057813d521367cca316c09c2b28fb3973826236b01c1f5d2f905d8d22b0c3c47f957a9ff5d7685591f15ccd7 +DIST smallvec-1.11.1.crate 34831 BLAKE2B bad85ddb1d3a1fcec0cb6aba413f90695e0aa0c16b2b231d6d15095bdd6de1731720ea2b394c3f9a444d6d4763bbf44cff389a01aef3488dc599d2ea63ddbc36 SHA512 d4ed45e8867366072e77f23ebe8b31be96be37e5beed30fc2b5ffea81ab04a2ad2aa34fb4f29724b02a5eb90f8b1d8c40b800ee915453947f90758ce999704b5 +DIST smallvec-1.13.1.crate 34952 BLAKE2B e0dcf1d26883564cd4f5d20a588562404e193075b1ae011f7f7542009a9466e5df3ade7768e1a8feb8806774b2cee5f15d31779928f83714e7d4b6ed46af9ab9 SHA512 1259ef947400470b8c9e74c5582dbc1a49753aa46420883c1f7d66f320f67bebe733a15a23cd57ba461020fad4ff337a5b298de82754602a78f5e6cec969652d +DIST smallvec-1.13.2.crate 35216 BLAKE2B 31a268aad595c06cdb078577a97b089dbea156a0df307a3e6aaaf4861bd9a680c5b11921da9dbdb1bcfe17d58c0cbede1ffe6bba3aef59b384fb1b9703c62d27 SHA512 a97c758b668e40ad9eb572e65feeae4954e09200a04ab92e26a13b48894381cd3a3d2571070c4b7a5e181182e1ede9688f990650342ec69ecfe1a264d234c679 +DIST smawk-0.3.2.crate 13831 BLAKE2B 551ed3406db797765034e2ba53d5aa75eec57cce608097eaf0f1a94fd1df8aa8bd248087a8a3b037d844fc91773f74501686180802a6d75165f771ea1f20ba96 SHA512 39f3cab5a6eaaef6f4e7703a6840ce7a805f6175e02968090a58a12d3420f0a144533e5d6542f1e9ec0e36902046a180386548713ef6148064922ff837fa1602 +DIST snapbox-0.5.7.crate 49447 BLAKE2B 9958ac5a7f5bfe3e3ff523c4774855b60ad94f8d0862cda693397333a8f9d0ca1000e7db01f8a0f55cf9bc88112c52087e3322c506f6cb23e726e3aabe997225 SHA512 d081815dc650b8ec1d565feaed21e88fbd006142bc7de8925d3936b9a80ba7c9e7f2c764f970780d7622107205d8f0414d82f1a7653254d7e1d128dee2913420 +DIST snapbox-0.6.10.crate 53111 BLAKE2B e94b2b5a39d9a994a8301f32131cbbec846911ddaa4224f347368cbf140ffcbd63d8e071cfdb99f7fde9ca0ca8a667026964e5ffcfd12f1182848b866299c4e2 SHA512 55983b0c9bd5d531bf291a071aeb0cc7a2a618480f66a8c852c8ebbdc81aa46554085daf98a2f349f17caee23001b5be73a2ed995c09673cbafa5f4a5281d307 +DIST snapbox-0.6.16.crate 54140 BLAKE2B 87e5cbea3a65256bd645127cb7f4c1beb09a25422eb3d043773312f65bd0f079c53c3124778a4ccb0a05b60cae8ae3222b1c28568d464748385d7be708f14f08 SHA512 f00003bd5f166ca3923979d662ed06b25859f5153cfa2ea9dd058b9409fbf3bc0fd0ec4c6b1bf466086f6dc5741f3b4c641d8c9a89ae851d7f5b38c1ce084877 +DIST snapbox-macros-0.3.10.crate 7129 BLAKE2B 74bf3d2b0308ecc70dd935bf5a761a9788de2c0da14277117868b892d0ed850018cbc234476a8da9840d5a61be42b29cc8fd51a0d81410f15bbe294a11bdca9d SHA512 560a6d6d236d24cf9e8b59a31d01027cb25beb26080820edc28dac1e6e9392563e3f0fa858c19d47b22919859ac13551266e648d0eb47a434a2008196efde410 +DIST snapbox-macros-0.3.8.crate 6328 BLAKE2B 217515d52debafcda4bbd3cca583c4e029758a54640d726c2c0230062cbbbf4c4b0e97a82fe56a2813a793f799879d8284c62b3cf985ae72e399db7556f317e1 SHA512 a0d4d923a5b64db9794b51c553e011af80ea7f86d797a4af8a81c7ac097808f42c00579225cecace46aea9e818d3b4fe00ebeddaae291c3a4bed61c77e6bbfe4 +DIST snapbox-macros-0.3.9.crate 6453 BLAKE2B a076217e83826add6467dbdc89553d21a779304225ab3b0d3c16bb2504df11700f8c1d45972c0706f737d2aeb30c4fdaddfbed185e400cc9c161c88994179d45 SHA512 afd84441660835b7cb884436f96e68a1c0da695cbeacfc4de5b3e3bae95221bbb7cf861778e2a3f7c20ebdb7df57109b5923a45e2caefe4502590f9072d3bcab +DIST socks-0.3.4.crate 13172 BLAKE2B 02fa5e950aae0ae6fadb11f27c455da2ca3ce5db3b63f27ea720bb748e03652038a599c036941240edba0286b61a35699bef8db07716ada851c1077b0592b7dc SHA512 531ab43f277e2dfc6aaefcb584c5fdf910cba51cc5fee73256ef00dae714ace844251cb53ca090fd3e8258115cebbcf65843476913fadba8535cb44166294eb8 +DIST spin-0.9.8.crate 38958 BLAKE2B 8648bf2e48fc618758e3de67f0a493bf3cd22a8d18666164b0d850ed7c0d73650f7b0af783019dd361116bd60c61d24895cdd2c579383cd2700de0e32a23cdae SHA512 b15ad66ba9b308937f34ea166b799676fa45c67224e10cb57530fe33d2a8317ff3e3db3223a3249fa2862cc141c964d2130d3f39910a86ac5ef8aaf8ff4bc6ee +DIST stacker-0.1.15.crate 14656 BLAKE2B 972e5872b402d0572686a617ad72af69a3a19406f41bfde3990949a86a4410594838b0a1e7929102bbd529dcf74fcf2413ae4f9d1cdb48d1c069b8cb4319c0b3 SHA512 536cf41f4dea57541941dc89c61e82af3008d0d847243238d622d2e64bff595ebbe077368de87b3844ed0f06ced6cf5b03100e07534f6f5dde7219994369c988 +DIST static_assertions-1.1.0.crate 18480 BLAKE2B 358dd5ac413d06f62da0388e2016c5fcb8ec68fd7dceb0dbbcb97665c032b7509b7e083c20701648b6a9174485f117c02682ae4bde7ef037e80a85cdf6a0c86e SHA512 46d0e35f77941dee6f60f574c130472248063dc38494c1c4f84f7c048244cc2a58a86fe17c0990e3f0f01406b75ed385a13d00058612b27cf0e867c8d31c92ee +DIST strsim-0.10.0.crate 11355 BLAKE2B bcb25ad0a7284e24e4f17ebe0ccb621bdc4118e499b50b094d98aa7e8fcc0b96716c9953c3516ce7ea78309d41d424892ded595259696a5bbffdcb07802b5c2f SHA512 78b318532addfcf5c1ccc1e14539e258aab9d3cd893cc45d82342549bde838c177d90f13c560671f8f32929af47d0b467db35e6876bd7697d8b3f9e055aeeac1 +DIST strsim-0.11.1.crate 14266 BLAKE2B 252a9ede4241b165525486aa8855dece37af77f5b28e0e1858c4a5d2047db9fa958328db10989234aad69463ab51b2303785ec056c63ea8c95bf95e111ddabf2 SHA512 0cebe0155a92640e56db9a599ae62078cbb32e1d2da8bfa67ed0e8f410a7558dfcf7b3c2720ff5913282e291ecf076aed9fe9bf84c8d44e814a642b1bed3335c +DIST subtle-2.5.0.crate 13909 BLAKE2B 660c3a472ca54c9843ce3feea74b802e27fd7f62dd37a30e2a4ba82e4b3a71df63562e8865d5fc675d31d0900998a8730503f91a61450884446a3bdd6af0041b SHA512 f150b1e2037554f8cd3213a54ddbc258f8f670cc4f39e7084cdea4b47538dbc58b834bc93b443d58a4b9087224efc003234042aaf366687dbd32b1e7174082a0 +DIST syn-1.0.109.crate 237611 BLAKE2B e827445d00c79a8eeb91eacde472f1987addd6ce9e1df95d7abf6446a77ff4173a8006845f3ae71c1da47193cfb72e0ead9a6d6bad2573be12c17e90735d9ad9 SHA512 12816b9e8cf984024b2fbce9f0ae14cf94d4d2c06f08cc54fb793ce78770bb4cc1288eb7df0ba5e8e937756e1e8e295c53fe07a0c5dde1ea8ddba03b6203b37d +DIST syn-2.0.28.crate 241635 BLAKE2B 5784468a0dd04eb298821ae5a3facf72c5fe5907cc469919b0a0b636bb55bd15e9e3a31c9ceb05b7b0f88e7a53e5891e6874641b61e5fde247a91361ae37047f SHA512 96e83979e70e2e1e46ca2af45d10fb259847d61e327809a51351a988282be9688a8c4942a284504674c8684970082dc15cd9ab9b3584bbfa68ac9716e071f9c5 +DIST syn-2.0.32.crate 242504 BLAKE2B 2c2938c0d711c684c9baf95538e2e76220418646590474b2b654d9242d2818aa7c3e5990208fe231ef64903df17edbbf6cc930e6224c964cad4eae5aeaeae781 SHA512 609f125f8138d17b1185760b1a63f3713079f5214fb56c23012229a56d10ac1c12654466c9ad1ecd6b2aff1126d125abfb0a42bd7f669635e5024b962b0cb0af +DIST syn-2.0.40.crate 245201 BLAKE2B 70876ef8e459f582d8045e46fbee7cc00088693d7d6feef1c07bd14dad3f6a555fa97762b8df018847bddbd2e9ad432a2640153adc6eb0e6d9bac821910c74c1 SHA512 27f9bda7df0549142ac0f732387182d5372f1a49facb2c5f20cfafd9b03afa0ed8c1e35b9b6f2659add33f01f00a2bee24de3b5709bb9238503e0064b791e612 +DIST syn-2.0.48.crate 250566 BLAKE2B e46b0863af76c3116c84d01b654a9820b7edc51f75c9c5301a7967d12284f78da602409f34fc40524728350dc6b998a4d738f08b8868f95236b3e5d24c460580 SHA512 926c0ad55cc743df20f9166b6d71fd44421aeb1f073fd86b6ddb53e13cd508b539c0360ce64b07b65597bb14639c8f33acf7e60951e1e9128624517aa3aee325 +DIST syn-2.0.66.crate 264855 BLAKE2B 5029091b2cfa88e5c739be913a647dc9492696398c09b891f84089350e6f09baafd9935b81e0f3519d5465eff2e1822ef6cdc96c15d6a40d1b6b8dd2f9e7d073 SHA512 60a617bfd37d74c52e4d4d63ef0a27a2f9b982469a6926922f2f6e96754a0c66affb0847b9a44d505c053cbd788b97e998efb8d1e558ea00ae4a0b7f15bed9b0 +DIST syn-2.0.68.crate 265035 BLAKE2B 8bc6f68ed286bea617a2cfaf3949bb699d3a0466faeca735314a51596ce950e4ee57eda88154bd562c1728cfaff4cdb5bc1ba701b9d47a9c50d4c4f011bee975 SHA512 7b781f8ea2b0d01c06f47d165da99cd96e3b44a33de1d77c78a2cb37ebe3f8304f426ba3d0d1cf766241dcc0537908774504df7d455d63bf89ec22ac0499d372 +DIST syn-2.0.72.crate 267069 BLAKE2B b0b979f78937a10a6db45f96d5d93c595427a4e158d658a2186419d89b219a4a405ade488d88d9ebdbd605ce4b706aba7088ab39a77294f3cf9847bf032d8f91 SHA512 c3d26bf9787555bc6fd8bd789855d252e80ad28a413593e13bad174adf86087ff195a6b4227bdeb6d1a1c87b0af8e965d6f2d04b8d45e7383b6de49990b92e89 +DIST syn-2.0.76.crate 268798 BLAKE2B 5446965c6331fbb445a313ca8da9d8e7454e31d9a36c2f595747edc65c0d2a05e9d8e4e9fb6dbb30da8264c7db36b1cea14110201bb06e40bca69b25c3f79f1c SHA512 c633b9f68e67b3cbf2432d3648e42f8d92403877a0128becd22cb108c0cfab9f1bc6b941b9cde225d8b727890e9f86457fad05b544fd07be4c01c2e60a2cdeaa +DIST tar-0.4.40.crate 51844 BLAKE2B b51c771611c2c1bc6a36d25493dd775bcb5891a2e4a8ae918781abe66c0335a3da30c5e44281fa5282dace34c09754fd2df840c0d74e5b0b4624a519fd455a8b SHA512 90bde0dfca91b6c304d5bcd4c93c653c066b76592927f5ed3025752d6d0244c0d5786c44af99df94dd6cc7a417663205d86f406a3b60f7307ca3c1757239bc12 +DIST tar-0.4.41.crate 51871 BLAKE2B 7b24e1d923089cff48e7f5be141838f5a3db78477ba58304b7a076d5d2eb31525f307d674546e0023e78836f992566646724870eee556db50e96d5a0c851cbcb SHA512 547d4a10cca5b593a04e3775bfc175a3a4de27f3c4dede305c6d50b63b4eb38152c6f06280098f14c4fadcca4cc9aa98626ea50aebe9bab2cb7b7f4e0c4d2b92 +DIST tar-0.4.42.crate 58998 BLAKE2B e3730ff969052b328abdee9c1413540a6cb7829ae08154e2ffa6105876b459eb610c7e9f1ec51a1b64ef64e4d550d102bdd1a0a1a7526600c92726cd6be3097a SHA512 f7ec32f1d5b5b944159d07c0ff0fdc03efcab07f3874a368dedce2920d53c075df131dd41fbbe1acb315a2093de7a5d9564ee382c19b77c528ebd4c2710f5340 +DIST target-lexicon-0.12.11.crate 24594 BLAKE2B cf06720caecb5b5758f05c6375fa600da9260aac04017458060406a042dc578d51a2c5b6f189345d45dacea42ba01fbe46853d07f70d7b37cba17d87aa101f9a SHA512 f38701a8e9dd17b7db591b1b4c82c3b75d317e003262bb7b09b9cabd3afab5ab79c02a7dd524910b6941ada3a8f1378ea9e199b2b5938f8f01ee75bb0eae8718 +DIST target-lexicon-0.12.12.crate 25156 BLAKE2B f3803596c75f6c89438592a1176c3748fc2c0524d7d50a20056de1cd26d40c572b05bafcdf6dd702752864bea37c8b4f28f96dadc12a5b3bb1d279b25e489f85 SHA512 6147295c43ba1b7b087a3c5ab51534b2985e4e77e5e15687978cfb9d07e21c4fd9bc7191576d6cabd268d08a44dc733c4a957e59dba8b948c2055d8bb433aeca +DIST target-lexicon-0.12.14.crate 25508 BLAKE2B 5ebb6b49e5c3b0057959557651287d4bf5ffe5b499340019ff64d5fc3b64e780e344982e358c94b1b25a20bf0f526a584aeecc704695b50a55cc268dd65edb97 SHA512 3410ecc0faf854f49c41c99f83972960e67065b1e0e78557a7c4996d996109bfd167d2121a019f5256f996c896cd45af032038ab7918fdcc6ee6311693ce951a +DIST target-lexicon-0.12.15.crate 26384 BLAKE2B d1ba50aa9d50647c6f778df86b35db1a4dee56fad918e6ef216688d9ac716dc5e8b40bff15aa89a99e4874e74d7e2731ad7fd9ea7094652def8abf57b74f9811 SHA512 32cf3e2da1c28003e1b6347abc8ae4d8182bf5b719ef84772271fc871dbaf96ec98c03b555a748cb8ab76584e67e17532757193d1d84b057cc90bed525727fb3 +DIST target-lexicon-0.12.16.crate 26488 BLAKE2B e7950e4a302059a1bfc9bc15618a3c1b971a17cffae117a6e8f5f63a0d82fd2bd02680301d15338612d5426d349dd24cfee30ee787a15a7d3187f2a6825e69ce SHA512 092639957c4a0391560b6442b31c47159c04d12e971010f730a6ec9cb5389e4be903ef3d7daa06db95e64dc78b6970731fb647179ebaad2b12e9ed5e9b24da27 +DIST target-lexicon-0.12.7.crate 24402 BLAKE2B 3715b15649566b9f26fe02aad818325a43b54512008e4ea9fcda9ea15a87b8f4baf4ffd7343fc12456c97d8a6b1e121158c4cb61997de0e2d24d1bce93d86850 SHA512 0f3cdbd7515141315934b6ca61c5666f3bf60e259711f68ed3c33468e2bd400cedf824db7158a80fa07e78cc7ac2a0a1eed2df199352176148e9df34b06511a2 +DIST tempfile-3.10.1.crate 33653 BLAKE2B 819b183e7840f70270883ee8b6a91fa09861c3112eaadc65007199885abe099bd593e1cdc4d9ab48c23490a6d484cad9bf0e80cf4e718c369cc2418b72eaf09c SHA512 bac7515b85b0d01ea914b527f0fadd3a4d8e77c9eabe786977d2625d8a3e91decaec502dd15bab4d49a43597fa7cf7660fff4be1b043112d13b542a72443bf39 +DIST tempfile-3.11.0.crate 34153 BLAKE2B 3a89580e05600ff2ef5637d2ed76ad8f1a769f6dae40cbd23f7bc2cb9d0807d03713ce1571df54c866c8fd9a4fb073990e4e98cc8ffee33aa4d8343c2d39733c SHA512 47d4c48c4f90d116a2f7d5ebf29ea623fb0a0fbfb1192aaaa53a83218ac910b6c836d6d4d8233b07d06e14de70fbf30d243152b7ac22a03d180905c53b6ad9e6 +DIST tempfile-3.9.0.crate 32182 BLAKE2B 4e802990988aff3ab5173bd96dbd906651a8df46b2619e6a500a3b9e7f4a3cd01dc7ee977791343f7875afdc4793a845000bb363d8c1a6599aeb6b1efcce5d56 SHA512 04e06c966bfa7a1567e7185ebd5c2876b96e46e36af14931bf0eba63795cd20d1c3427b6709a4cab2a68b8d289fdabd5537a50e5407a76e3a9fa0dcc7d3ce6d7 +DIST termcolor-1.4.1.crate 18773 BLAKE2B 34676efbde8e242415857d6d40a287ae3459678d8222f5144faefb8c84d635686f640e79588d98635c8f25b7628ec6663a01b16e1e462705b5cba7e8b8e61f44 SHA512 b66aad157c4fa2985f764321d157dfb1f0325fd633811870db7919b5579bf7bc19fefe99e1c706cdfa67504c37dc2ca3d283e11d1bb516edcfaf1eb7747a778a +DIST terminal_size-0.3.0.crate 10096 BLAKE2B 097ef50a85945128dcfa36d8ea0fb15f11142c206462a32980dbbba4fe2872abd214823fe3c75e804f3159a97d6e929ec338860e9c89587da509fb9e6da5d339 SHA512 f3bc9144aa8a87556543584a2495df6267ce3bb017f3ed3d00fa43e89b5de783e1285ca62dbad9dd9c3b37e3a476a6f3ab0804eba2411cb594a569bbdb310681 +DIST textwrap-0.16.0.crate 53722 BLAKE2B 44140aa2dfd5076005749449a56e920418e71e34cb92f1d697eb3f3e7f6fe87b0a3861c8a4050a4a62e03187b6cadc4495e4200bee52ee183541431c73e47209 SHA512 97ae8acece5663e1a6b08b827179e96d5ad0ee67d635888cc3d83454b52cf48fce97eb0eba374ba4747834099c74f43d66d9fec868e84be45369a42c1aaec2c3 +DIST textwrap-0.16.1.crate 56012 BLAKE2B 9b5a7c76eca64d089f4fab7095f2d35624527ca223e53b03cc807c6bfe913a99b55197b973a3102e3e5c4055bcd6ab580a0c9d67657180b61435bd6eb7631211 SHA512 3a8d2036c8e4b88866d68b8066a2991756f6bd4ac5c726e63fdffbc894fbdc03bf8b6e0ece4b96684c8e1facb6413190768d51a8539094efe47977c120d31f1b +DIST thiserror-1.0.44.crate 18760 BLAKE2B 4afb9d1cae98afff52c2e9cb67b8bd75815092f87d51ab5afcbf3366ee6ae8fde33c0bfab9458c9c452aee3b324894fddce327475ee754afb9b27794fcd9d279 SHA512 3a8e9346e69216510337e2c27e91e08e7a42a8b6b2abaa776df3937ad4dbfd857fcaff26e97d89965dcfb2003df1f1d1ff88eb239d334e62c806e8d637eb149e +DIST thiserror-1.0.57.crate 20993 BLAKE2B 4eb90b8ee027e39102d6c030176db94510180f2bd2966503501ff89ca6b49afd61e6d9e1ebf18c08d374ff9de4e958dfcb3da8740fdfe31cceace5be456bfe4b SHA512 0ff7e48c3696f4f4c6af29f3142f0a7bb88a07b7a9877ec243e3ea15d89c48f1898b731311da5d4a7c88060628cae3eeea6a4eccf25bd851cb3075920cb1a936 +DIST thiserror-1.0.61.crate 21264 BLAKE2B 97337830507c009dbb4cad84cdfc02bc097b9d39d0af2fdecfaa63f0c12229e60727244fa4e44c2d54daee67bf8b4e8492d94a5de55d1a90b8eeab8c0d082e80 SHA512 9c08b868eaa47178ee60733aaeeda60dc46d58d2b9c15985ba3dcae4923e8edf02b97556df52f508753b0ff52782f6ca3227e9ef6343066e5d5d3a89e03f3f15 +DIST thiserror-1.0.63.crate 21537 BLAKE2B eacab5745d948416bde165d768f55c10c132572052db405ae3dd3e6e3b5ce41f36d574192ae68fecf6002ae5b14fd0aa135fe15e1614f3b51a294d5edc67c9ac SHA512 d5c2360075947cc0fff3253b5532f03f3102d6c9ef52dfeb3b400771116937e466a62ce67ccdf91532bf096f4882322522349a727588fd87b932326c8e758753 +DIST thiserror-1.0.64.crate 21574 BLAKE2B d2c7cd7c1a8850dcd3f188aa1af61d4727c4bfc27a069f0e743adf86b7934e6db85d9ee9af14e78c7391e99f4ac828c00277a1354bfe1a47ddf5964211bb2037 SHA512 cff21ebd9d5d37e548c35dd1dc0e6e885a47363cbd8ce3cc8508e8e9b5f844c168b9f3d9ab12ca8d5910a53a9e09b4ddc75a0c32f983e27727fc104e4ff77618 +DIST thiserror-impl-1.0.44.crate 15086 BLAKE2B 664be3bca31bbcdd2bd8170e5e769d25e0a27c135067c84404d94bb51b5ef02daac76538898969281b0b0309c26b5ac4198e7bc819dec457dcec09e65530f75c SHA512 fe9211f50dc922b957ec3b9b5f132f812fc51fc68d23ad39837dfc174220dafb2b29d66822f34b05f1cd27cd473598d43e17979ccd9c70b056d509cd5c5c9ad7 +DIST thiserror-impl-1.0.57.crate 15639 BLAKE2B 2838235c5536fcb16d19382fe286850d6fb882b1d77ca4ade6a62e1d4727ef89f69cf0383cf330996f9e2303226d5fd709557331a45c9a91393db1788fbf4422 SHA512 a850806f09b232546d1e0df5e35cd961a8aa32f1d8ac3b24df360981da53b75325a46dc788c994042c95a5887fdc77234b9f6ee5851242f734a613e579548e3c +DIST thiserror-impl-1.0.61.crate 15786 BLAKE2B d63773424aa047c6eed8a6c9bcc8dfcee9841a2d4fdf6fc2c117695c09359371931722198b2e0b2bae32b0c54b6275f964e679b78b8bef1c365ca33aa41562c9 SHA512 b43bd2ba6b751b777e2fc78aac92a3e662a1876f704625c4e894019fc68a6b7628b9c3b7ddfbd2cb15fe6fdc0ff679ff94b0c47e2660a40919000ad2fe1cfeec +DIST thiserror-impl-1.0.63.crate 16047 BLAKE2B 290b56ece5c592fdab4d20e9ebcc8dfe3f76b00aa48ed6c216ed0ebcab86b1ab4b4d676d0f52329abaccefae12bd47b4a81966901fdcf4ca5d0632d5021adbb8 SHA512 f93b7f89784d72d8b6e36050c22b88b7fd8de38e9a90fa6fe3f45973ea1566ce8bf82e959951377e3bf584a32afc97812188be25983a028be138b1700bb8c102 +DIST thiserror-impl-1.0.64.crate 16073 BLAKE2B 8b0eee3d70f926c2719d084676cd14674dc5cf7c474c72e3e628a3cdda7afadd67a78f76224d2a05f1fe04ac59a178b879e467bac1981fc56c5904073153c88e SHA512 75e55f204a290eb38b2215fcdfa91f9f1cb002b121ffdf56bd5f6d75476614e3ce06360da7d74b870c45f6b107fa9e61f85ce39c0e65e713f8c191d79f96f443 +DIST thread_local-1.1.7.crate 13585 BLAKE2B f497dbcdfaf7dbc8b4b0dd97f77ba93df15b63303e7894c9032c9822a5b8111e0a21db2fa8cfdce5a503f70959ac9cdf48c840b925bdd850dc15e8436ba72379 SHA512 3772452c2a349fb564d29bb06e13c8ae64807db27c3ee217fa04fd0e9847e94adeea582b82ffc2d9116f31ff478eb088550caf1346c263de49b55fa17b431c31 +DIST thread_local-1.1.8.crate 13962 BLAKE2B fce2feddaaebde42bdb83d814929868f06387a4fa25d5becc73ff0b983395aabe076268569c6a89e2d90ce6e68d2ebca7c3e0ba1c9159c61b32631ce39289a9f SHA512 6d7e3941f43c43ac091db5d1cf2a8a3892b54b0634d9200426eadeb82015566532f04b6040085dbdcb10580ac724b6ded8416931d764d795a5f923aced66c492 +DIST time-0.3.34.crate 118430 BLAKE2B 6d04a20596c9b0961ca104748d9d360f07b16059719d7410fdf1a7a0d5f2aa02aaebf640999464835964bbded2d3257d79c4b0ca3080fbecf13dd2d0aa6962fc SHA512 3997e1b8d9be2f54184ebc9e1355d4b65f0b7bc9439b2b29e4a4acd86ad3a3aa019261112a24d998d76a7f66b266a86536fa50412279911b14d4d7aa7078c116 +DIST time-0.3.36.crate 119805 BLAKE2B d4da96368ab8565373d034edce261e0d8867036f2ba87e84b5e4a506a70ed3b62b93ba10734aecb39847e258cf7008b6ae57f92df8d0e5229cd3fec488d14caf SHA512 83da6e27691d1f0ef37ed276528e927686a06dab4811b6e29d625ef7a0f7c30fbb86896d74a2b087726e7a24a951b0a83aa1f5f22d711ead54f447d36ac47133 +DIST time-core-0.1.2.crate 7191 BLAKE2B c477ad3410ff29f3bf4a38fc6ac4a043d49b6d2bdf5cf309ffcd2eec3bb6e4c4b62156ee7f069f0b37ea31c163bc75ccbf35abc1db2833cdd4912135e60ddfc9 SHA512 3861724c23cb806829a01186deb5217ae8252c20af622975264e6670cff528f42155039e4937756a9eb312a5580ffab07949437d5504d684a0e70755046cac52 +DIST time-macros-0.2.17.crate 24443 BLAKE2B 5045af9352961db0c97cae2f6ca3e8d2c4f89a129c7ac2ec1d8d20804292aa9f2901a61f910a564954614b68f39311bd381deeb66fed8bdac423227d077f3d14 SHA512 c81747f0b74e68d3b3f36d378ac5911dece8c6b511e5ac793807f854cc31c812b927d0df941f55ff90d3d67512d0ac6a5f63f2de4322c81b05da42f46b4a661c +DIST time-macros-0.2.18.crate 24361 BLAKE2B 09fa325be0b1a5b922285f035484b0de8e339306b49595c87f6374e46459d6777c6db4b12c1a0c6ea9795ae8c741188fbb81208d0499a651760b9f5089323fc7 SHA512 557786115add272290be8305ab79c44f5b4425b64eb698492fe300f15879d9e013c66933cae8aa8faad9c109e2917e7a0e43c8a5eed7f4b0f0fdad092089efe4 +DIST tinyvec-1.6.0.crate 45991 BLAKE2B e9699d4d80a78978f0ebfd049f5b33d7f23d401cf4f4439ccb168e8c0e322473ad0ea7e2ff0ff69e9aac3e5c4c9ae5a7102185533bfbf96dbe77b3526e700bc9 SHA512 e5acaf353c58c60ae5556130a934f1048abb79cf6668ae467d308bac44b689d8a9997227ea879f4b5fe50f29cde8761801b088d7149bcd063b973056c381921c +DIST tinyvec-1.7.0.crate 46743 BLAKE2B ec9741aaf6900ed2651c222d80688176353fd2ba99ef54db18059bc527b638fea1e9d0ed03b18a8c2f3a4732f94dcfbdf1411050f1d744da5d88cbab569b88de SHA512 9628e5a8861d01e22f00161b3cee58861a2801cd0c64016872bc0c6fb49899a553abd0bbed61064ed91e3a8fbd93e311b2a622fd21d74345e80ec27c1e2f36db +DIST tinyvec_macros-0.1.1.crate 5865 BLAKE2B 2bf4f68ca11dc19c72232951605a4c809b34ff38ee365ee4f592a3c41360e23c9330cfba961e2692a0ad568fef4aaaac51c40808d491178cf7a0c4b5a1c5d484 SHA512 10008c7b3a3d50c94b9c370015b76ee082f5dfb6dcacf014dc2f2dbe92f903618d10d0202b21f48fcf98a94ae76fb712db55a5e8ad353645d378cf0e6ec74f7e +DIST toml-0.5.11.crate 54910 BLAKE2B 9ecd5103b33ab47d4be23c897c7095ca381cb79bedcaac4918cddc36fc7cf5d34ab664da52c2273d935f04486e9325241d6b66785d50aac78453c219aab49e1e SHA512 eddb82aeb8fdeb5436579292c6f7a64a90a2c7bb54070beb437bc7890b99795d0505faa8d6451a99e8bcf440f78db8a1b273a697c8ad44275cc4163a9ee49317 +DIST toml-0.8.10.crate 50667 BLAKE2B 815c850d4e2b8f107729c24ff82a6be81160649fff726f07a2c6e2af0283298fd5eadcc5811ba4ef20ce12914ecb43da79fa1840fea8d1572ca59f02f9e2c310 SHA512 24f3b44244d7e91ae50eaf20bde40c177352592aadd2dac697a831a5de9305ac1c93c8dc407579b9bbd8d9984fe34cfdc42c3243cd0057ad83db14bd899bb546 +DIST toml-0.8.14.crate 50645 BLAKE2B 264a757d09f443e9d4d2cd7efa07bec4bfa382d1ca82e59d268c0099114547536858be323e8004fe7add72967b5c193bea176a823b688ad8be2bd71b186607f2 SHA512 31af40bb5d8a172f45b5f0ea7f089862cfec57bc9bcea6559932b045efefe9e8be349df24f55d6ebe536f414fc35950f6545a4703e13a202212eec9fed6ecf62 +DIST toml-0.8.15.crate 50652 BLAKE2B e2aa6e1efc9f5d730659d79c9ccbed7e3f6e2150cd2f3e00dceb017e61fa24ba69dc9cf6b9594d89d23791914e4b7016826875644acc523722f3b770aa50c6fb SHA512 3aca72fd693d3d16fba005a03934c2473c72e175425f0214b43f795edc9dd75fc855daecffbe59279608931010948b32aa720a8411f8b6a68a06e27763e4c94c +DIST toml_datetime-0.6.5.crate 10910 BLAKE2B 93a21ab2784e96ee2e6b56c7b4f733f6ac4c68c1e7d7dac3fbd8aceedb3580e25b4a9c7d9c3f9b5ed152560353b3e80906e37824956dc4ea90bc6f039768f6cb SHA512 502bdedbcbd2ac9fbaa5f4b51f2e409af185f3633f01f8845de5e3b007f2400215ddeb82ac588bc915ed5a5f9d7251ccf93fe2a57cd40fca2927f4c0966357e6 +DIST toml_datetime-0.6.6.crate 11698 BLAKE2B 8db35da8a3f6fec053bc82995f4abeb8d2855f2e94ed6ef4a4a6f47e956ea2cb6f8d0edd5c1b1cdebf83c7c218d9f2d80f48346e62fa7985532cba925891edd5 SHA512 710182bcca90f0d830423df41ff0f8e7bd10b866fd7ea1f6d37a315c7b4732a3b6fd61cf411b28051959034534010f24e250e10282c4e5a2539c2858f447aca0 +DIST toml_edit-0.21.1.crate 101661 BLAKE2B e794b6121ba7e2b1b3f50966cd40eebacee6968b6b28986cfe4cb7312b51ffff19f74826910d8e4ce307f74940f11e71e6afdd768ac196427bddf44595bbc797 SHA512 10cd3b16f763f55294923ce8f166f96fbd67a0acc4a93a46fb3044d8a38148097c592ebb405ced87030d35154abfcc971eacf0172b624ab477a11e616efbaa07 +DIST toml_edit-0.22.14.crate 103761 BLAKE2B 54acbfda77cb071d280790bdf167a9a7a3fc6c8297ef96c5a82d55c93fb036c0ed167fcfd380d558fba3602bfad26080947e6477a6011819795d2debb74e8d14 SHA512 fef6ca35315482f635bfe35c2c6753d09f9bd33681d8f032f448fb9c6f494d30fc5789d96f99657879be9fdd7b35a640d52fce7722fc6ca05d8b9d5ed91903c4 +DIST toml_edit-0.22.16.crate 106618 BLAKE2B e461b46de9da1fd443588811ce788875f3318dec3921a048cc84b3ab1a5a75c773918e85578a5185aa3d713d62f6e90c3764a49d184fe48ebc50d6a127d5d8e8 SHA512 338d3aae648a4855503b39f10aecbfecaf63fabc3cd904d42e5859ce22af840f734b29440bc8b72a31fcc3c689f6d8417ee4e3330713d461b5480d30699732a6 +DIST toml_edit-0.22.6.crate 103304 BLAKE2B 93f14ec5e0765673b4621216707605d7c2afef82d0ad9fe1e0c660be62fb65a59e91db3144c7bf04c71cf5848dc970447b3b31255125d3a2be94ababb3d82692 SHA512 9816338008f2727fd53d34164c0be16621b61e22ac4838752839af4bd09e4d361f319bbd188c5732c1af140358d73d645e05faf4d655eb295d6c331293b7f2d2 +DIST tracing-0.1.40.crate 79459 BLAKE2B 33693ee71564fe5925a63dca351e838dfd8612b4b1e49a33a70095e56ca63287c13c772661ace0e540d08c92942d7cbdc51ff2cce4f4b372164d9aa20ec05dee SHA512 5622188a45dddc0d6d3a8244a9b12db6221f4180944ce1019d18f4e613e4bd113dae5d45fb57dd0754f6e8e153b047cdf00c8f200782bb2b868bc2d423d99275 +DIST tracing-attributes-0.1.27.crate 32241 BLAKE2B a20af0f50a90dcd64e5318e55779142da294ba18d1cd40059a8aa964fd3c92834e03ee563e41caaeef71a30e3f027e5c8d167d90e2844da79e0774b267e179b4 SHA512 7dc59f4234c3bf3434fb352baed2b81db4e931eeb3ed207c4a204e480da734be40847b167b808058d2807b5583815625bcd5153e2bbe79804cfa6f069a74ffa0 +DIST tracing-core-0.1.32.crate 61221 BLAKE2B a7815c46af9852ce62498083103c6d359351f4d33609b4291330073b6abf4b63f5e1bb1a7dfed3bbf4d6913ad5217e96999416261af8a70609408a29109e4db6 SHA512 164f79cacfcca533a53b7dbbdc2015aaf851a16e00c72fbc4e5f515b6a6dedfa464e964810009b54f08cbcdc5a314e50245ac7b1b01a71fce4c63db135bf5521 +DIST tracing-log-0.2.0.crate 17561 BLAKE2B 701bdadd40f1343f3c4901bd8dd188f1dbc0afcdf50807bd0f6df7539635e239b5095696872103125a4d4cfec24af6336fce6f3931363dd5be4f53a09fa584f2 SHA512 0c1f060e8ffb9ff24cee7b85cc2d7d42c69b2f7623a7faecd7422b23b11ae8d5c7691e4635bae76861d444c369d9701ccb147904668023642b223e442e3c8285 +DIST tracing-serde-0.1.3.crate 7329 BLAKE2B 55d924fc3acfd496abca8b42bf3fa4a2511340cf2ebb060fb31bc0b5d81dcbbaa299daef3cddc3647625afd124b9c83efc1ef104f55dc6d4cd4d91e0e667c160 SHA512 3822ac747df404c33573ad2a5c722f9708066a72c2893dbf507563ef29bebcab79cec17515fa87c0fa64be8a08073c38ab57ccc463c74df8caf3df69c72e131b +DIST tracing-subscriber-0.3.18.crate 196312 BLAKE2B bc2f04da63b0313d26073eb4a39b549ae37701e4dbf1fe06a2483279a03d9dde981f0efea6ceb5cd441ab313bfe7eaf812971c3ca60dfd4b5d9cf0d2eb7bacd4 SHA512 72f91855637aa476f03077d5f523cbc94989d40b12d7328167f88b081869ed096e6370450831f6cd5f0686cae5628f14eed4696c06a2ec75f56808b64445e0c1 +DIST trycmd-0.15.0.crate 33990 BLAKE2B a206f2adca22972ba59b348db7b62b4beba111c300a7faef80483c9458221b25d2f6dc0f63ae75b0f6fa896dfda6487065374a2312ae493b5b912c099b81639e SHA512 4b63bac98a5c609e17d7bb6cad6b052a512799fe3fb49e68e4e19bb0a031f0098356a6a72582c115de636681b6826ed277ab47547f28bef2da692560c0c95743 +DIST trycmd-0.15.4.crate 32928 BLAKE2B 45944505a676c5d6e452130694955b1409fabf3c796bad054c32abb3f4fe96088b24344dba21986dfc93008b7c914ce419dd56e5ea664325c7860567b97ccd75 SHA512 cd397591721255f24b4d7fc9181f349bf1477480f7ad573939537e9e4f37fbb467b5d34e2049e8c917f8a00a10f25d9973364fc88c15cfc5ecccf31d2a0c00b7 +DIST trycmd-0.15.6.crate 33582 BLAKE2B d5d4df13d462bd5eb57d7103a60ef86d4df6f5a9cb7febb73656f0884b29f1bccdfa75201cd7147b565e859102e56025b34745c629dd66fa5b22b0fc86e458b7 SHA512 34fdb36f61f2332540e531485de0d065bb38ef74d1179f652eb71514bcf65a5e0c9258f4cc572cf2afb2f0e7f3e45c7075318ba1c20dd04e9a40d86a72dd2e58 +DIST twox-hash-1.6.3.crate 21842 BLAKE2B 67c261b2b0a93293717a4e2e07dc11df2abde09da6fe713b9d04917ace73de1b59b8d4fd9449ab46cb7cf496fad1e440effdfa1fae6f5cae4ca78af8cd019c42 SHA512 f7ce63e6e5ca79ce9330caf40b32578a5d2088c5d8ed371604268760d6e212d447d9e3a95378378a283024155bccdaea47597902c488a94c5d5f79770baec8fc +DIST typenum-1.17.0.crate 42849 BLAKE2B a6d1162050679e2c4ab2467f3a77d301f6861882eb7c9749f31d047f383dd5bd2ed5846ad63eed99ccc04d6ac36cc697a305861e1d65880b4d2ef04ee0a79b94 SHA512 99773d5d9f850c0602db4bb67dd062b0ade6f086e155216f1bb2fb6569461ba7e1b7c2f2af81ea8833bc3bfcf3fe5033edecb7c438adae63f59d3e30cf63a508 +DIST unicase-2.6.0.crate 23478 BLAKE2B 6e580108ac81b1cbee70e5bd331f43b12f266dae4f4f758bb8f5f073bd1af61943ee0de34cc27769525b19da8c24f8dea4941d0f5454594ab0cc8b78071ff053 SHA512 7e76a5f344e32c56cf87223585d87a56c79627b52bba0b29eb6de82de874b2964accededa8e9b5741f57944b6750fba5c61e679a50d4fd5a5646f431e2f4f188 +DIST unicase-2.7.0.crate 23783 BLAKE2B 2b74b932b45c9d5b984b57bfe8249496c192944e2e66916919177eac81c509e2d7a5d30a85ea58e8cd5a0b47fec746bdb18723f3f14002fc64af3a0d320a9e7d SHA512 c2b05a3bbd8996e1cf65d7458f5ad95de9797c8349484f8db04967bde15c1f057f62b2f7a60e7367871512071ed5076c0da042169dbbdcaf4d6c16cae62da828 +DIST unicode-bidi-0.3.15.crate 56811 BLAKE2B 1f1d372c86ec7444f13eb32baf13dfc8699b52156b265a2b53f40c0d771064876405451120fe54739a2679e6991caaf4f63e0644f03729cab814079fef4868c8 SHA512 7a21d5eb05ea8d691dfd54ce4cf7d3693d08067f7a88ef17b8c3044634f46411176b1bde1516c442577910b254007b247f5e40f9932eb601cd96cd574f9d9db8 +DIST unicode-ident-1.0.11.crate 42067 BLAKE2B 3c7cac3d2bf1cbf1cf04716a482f130123e8e6940f7a90a17bc62fca44ac0069688165538f5329b95a72f735b594cfb85e3250738393ffd1b53cb0cd95077d89 SHA512 9682bbee339fb987c9d0bb6a54406d37b28b5c3587372d406402e4341900fec97e3234cd03b5c98b90b6378fd533dc452cac3de90d3ade19c4b09657e4abf6df +DIST unicode-ident-1.0.12.crate 42168 BLAKE2B 4cede03c08758ccd6bf53a0d0057d7542dfdd0c93d342e89f3b90460be85518a9fd24958d8b1da2b5a09b5ddbee8a4263982194158e171c2bba3e394d88d6dac SHA512 bc1824e1e4452a40732fc69874d7e1a66f7803717a314790dcf48867eba34bc9441331ef031e386912e52c385645c25b6ed39d4f149973b5b97371b1b96b1920 +DIST unicode-ident-1.0.5.crate 35455 BLAKE2B 7e14ce97ac53a88ccec015dea690918a673dc5b49e44de7fdcb5421871da35c4f514c6db9a363d6f4bfcf2e9a61a50a593d345d0b6f388ea882b17a00cd0335d SHA512 d355370daac356d900cd4c0a792d6c0eff114524c4bffce4d7e74469fe2117883ee00bf0e27d950b72e88739473f2045d5f83440a0aedfede97b4d9163b64a6c +DIST unicode-linebreak-0.1.5.crate 15324 BLAKE2B dc560d5b36ed01357c22750feb7f09fd0f57fb0ea543180f6e31c0b71b51df4faaa70ac8482f9cd60e5d1faa5bfd4bebfbfd628dd5913c2c4a858ec04beeca3f SHA512 f37be2f7b04b886e95bb7d0f33bd392b78bb940ef9a01cec487062cf31ec0367306650fad7004df556887a324c714eeb28f697044aad9a429ce07b7b7344af60 +DIST unicode-normalization-0.1.22.crate 122604 BLAKE2B 3f3430b279cc0ce1595392c869442ce676ab097154c688779ebcf726e10c497df59be2cd7bb2f84f99499a9df0654760a10ac92224c17d74775aeebe291241e1 SHA512 a5810d5e9cd93dbb80e013997aa9d38e60834619483a6623eb2859ec5d59a5aec3fc4db123dc7f4e2fe9f2b8799cf6af48bdff22d69a00a23707240e8bf3bb3c +DIST unicode-normalization-0.1.23.crate 122649 BLAKE2B 22ea5ce3f5a2b371c3c8782321b1bbbee724db1e4d8c1d43af4e6bd8044b99307c227d93631d178d10fda445a941a485882ae0015a6e3d3c347e4bd465bbe1d9 SHA512 539f04010810d73fde7b0ab314faf813f3e7ecd2e51d7975281554b7cba4a8706e2b5523c4b7840568593652360ca59e9db0e1ce342e71c28db635ff55ffb0f5 +DIST unicode-width-0.1.11.crate 19187 BLAKE2B 6baf7f3b32eb838925e591792abfe11968206d177facefb89ef51daf44c18f3fef1e41c19a47b88b81be50667af626af2024ccc540b240fb6e1d83fdea57076f SHA512 ee06f4144525424327a17578642565f396802f0eea539b3bebc8d9627376a8bc6c5376d83a6ee577068e99fe75815bd765e6d49fb9ab9b253d00594bb15a5ffe +DIST unicode-width-0.1.13.crate 457228 BLAKE2B 757c4da5fa090369a26130b08440c2348f1cd1c0dfbb6770dd75b65eba797eaa65f5d683f0c2862cced06124d46a89b4825af0d990f6adc2df8709b8ef291665 SHA512 9781d6dab2c6343e8c28ec66b50cb4293261bb2114e122fa80ad2facdb23020f5b621c38030193b918669e58adf143808e5ab4c507c18beb6dc61e97b2e296f4 +DIST unicode-xid-0.2.4.crate 15352 BLAKE2B 80c327b39f3b8f2cdb5747cde968cfa1efe7b65b6bee9136adc881fa19f66aa5b1010d9d08de55a61b322d665b5b0cb0395e9ac471f6333c40d8dca5d97e123c SHA512 e67bd1258e1961807d9d5fe583a89ab5b82b2a529ecd32cadfc79aa5331380eb4a2db9fd96b74c8eace47f2f29021587d69bcdbf79f7e2650e92a25f7839d03c +DIST unicode-xid-0.2.6.crate 15744 BLAKE2B b1bad25897717f6346f988d5a7c90c51fb842da113f19aa434a64add8f2e637258d9fab0f7b871fd2aac02e83c68359fc679b326232793cbc804523e2bff5056 SHA512 f68e78484479a5341b14d7e3391e691265851fa00feeca53af745479af6aa9b4ce3570456df785c8362043db9b04e2e57f9bad05d8305946f16af405bc611764 +DIST uniffi-0.27.0.crate 6343 BLAKE2B 713e3a3fa6fcdab71e6b118ccb98a9158e4b84d4f5c2128051fbcbccfd73a82b4dc4aaa9b5d07d97dc64a3fc08da71589b872c9cd85fd451ba7c30419048bbe7 SHA512 3a247646e3461a81a390f197ae1648a4195168bf88763b7fa70c8b2da04266efc28323af7cb2813b9fb13d33eaf13b2434dd08e4fd036f22a645515856b2f1d3 +DIST uniffi-0.28.0.crate 7374 BLAKE2B f529dcf02b8a4fb448d89b5b9f0f3659195b2085bf2f736054e859ca2069c075cfc4649ccaad149a48063e09788c9b93e65040ebda2e06dacc907e6ccbebac80 SHA512 b80d3b7a865925cbd68b934bff95a24f412d178bcd2c25e7fa06d6e044c37bfe4d951a12fed7961c0f5e6eb9ffd6b41a0b4a26fe416c115008ad3ad00f52341e +DIST uniffi-0.28.1.crate 7793 BLAKE2B bf62cc45811108495aba093e7a1bc6b1fe93c827faff15a52158cdb5e1346e553aee324cf3ce5b01505fc6b976b37b8b4b90a8236e47afc982755f23a8686c29 SHA512 922dd163ed948213ac6523625ffec79bb608d874eac406c4a02b721136f3850df377e8f7ab5cf4faf3855074032ef6996017b218401215d4f2a36a05a21b0319 +DIST uniffi_bindgen-0.27.0.crate 145565 BLAKE2B 42a1afe023c864f88d8e3cc69fe29a7450e8057528a83a18ca9060ff8033df4aeb25468d656077eb6049c0b47d691d9d18d6d71aa86e972571043ceb5cd568a6 SHA512 24f6cbfa569e7196fa129f07a4c987fc51136cd9526dfdc5625d5ae38a0686188fe772241c0036fd00dc2bd6fdda0970ac683bcf831b7a26be5dd12d5d38fae2 +DIST uniffi_bindgen-0.28.0.crate 144668 BLAKE2B 28135e0e5acecf891eaa08ec495546c6384dd8146ee523c72dc8f64b73bfbddb4ed472e5c0508084d8b4b1a815d981c90301061978df738b93ee8b0d8ce257cf SHA512 e575a9af4677838b639d13d52ddc356cb2e799be334ef0ea978efe022882ad15d4df0ec47cb638a387012e3999519c817f5e0bd6fb79a1ff1f89351b6471ef98 +DIST uniffi_bindgen-0.28.1.crate 148914 BLAKE2B 91fd675b5da48899f0a3ee7ea71a681e6eec48bdb01903cda94f338554cd01711daac84921e28c27685fcaa13b54315bbe7cee20c303248c503e74baffddee1b SHA512 7b1219ce4a53660cddf7bce1e6b659fa7c2bcfdd884f76acece5ba64eb27ae4533b6d8de0d55993f2b1a3a40fffb380e7f9645d9139f97730073af720a388776 +DIST uniffi_build-0.27.0.crate 4088 BLAKE2B a805116ed67a5f0b9cda9c40544097ba62e9df6f9b34e74fb252187045a601a2b3931470c3ec59e9ade75b00364d9989c92536414caf83caa6673d9a7f510cd7 SHA512 9e7a4722cdda5b941fcbcf73dc3ad95ae0c9cb50c0d06da8ff1207049ec183e6ef110cbc7b07fd8797700f7a5e17df22e139a41820f40286b5faff92a4b1fc3d +DIST uniffi_build-0.28.0.crate 4084 BLAKE2B 4a2051f0dd729c593dfcb6878fe4eca571aa19d483af5d6579e13d25a89e4e51ecf5d5216efc5341ce907bce64b1465cb225dd112b8b9c6626f4ee83dab71911 SHA512 dc51789a37a736321ee7daab3ef647ceed64f9012cdb6a4a296a1e5599a051692743764f796e10f3b6d592108184a048740d5af9c3c6ed76b950a256306dcefe +DIST uniffi_build-0.28.1.crate 4086 BLAKE2B 2e6ff329a09424bf10ea07edfad921336568f10aadd04777dfadd7ae97c249c2c4ea597afc59b872914ffb10c0556d159af1b456f6a454176ce5705545b509f1 SHA512 b1335ef25cb40f975dde506b9f8ddb0100233e6fe65cf92a114b77dc4d16318e1402b681bf9b28e0e7a062ba181e6906236ea0389e9f0c8e76e373fc1373cfb6 +DIST uniffi_checksum_derive-0.27.0.crate 4507 BLAKE2B 57ea01468df52f4cfd7f2fb6d2dd558720586369e69d054c5e3128cda07f03b451444e027aa17e544ebfead8124cef9640a9ef62f4f5611cb7644728fde30334 SHA512 1ccba94c2a2d4f07e203865e22c668db744cf6d643631e2774c6f24a9bfcee6f842ae2e3abf0ce7c0cc309828484cc9ff6e95f83e1221d0379169a2331b54a4b +DIST uniffi_checksum_derive-0.28.0.crate 4500 BLAKE2B 7e378de3ccc3f04d2810c6bc4bf4fa1ac0a8363242afa8883340a6c9c4f2f5543933a7d36debb042f1da46954a17619f1f0f9c6f0db49b46795ef4b6b44c8365 SHA512 4dc10c795e90a99216bf80c17566099b7735535d6a6a9b698bed5fa04dbccf333d58f37a4e3a42626da14db0f5a8c00bafa02f008d157663bf51957ab0372d7d +DIST uniffi_checksum_derive-0.28.1.crate 4503 BLAKE2B 35aacf396ba1af712f1d55f9cc6b57d334a86372c3bec4b383192459c7a652121369a541d73769dc74b7b5cbe0be9856e52847a9a7853f8022cf3a54121da9fe SHA512 9d355b6768c04c5a7f079d449d72772c465595fc15d88d62d9f86386d0949032656472cac319c1b349b18f097f26f64cdf43f29e62c18bd522f4dcddf20a7766 +DIST uniffi_core-0.27.0.crate 40047 BLAKE2B 61a08b31e386be0d78bc24e223f8b87947bd772937c93cc3c33c4823fee79277499c01d34dc23b4c44c379d321b7d178f406d0049e6ac5a3bdcf29c427f508c5 SHA512 a0b5a56fb67b8c292d27867003aa98adad9decf279746f3d25132921e796cdeaed446ca47466156216558db4f94347760a3798dccec9734b635e9d497edb20da +DIST uniffi_core-0.28.0.crate 43726 BLAKE2B 17173aed6344cc537438524d7373cc8c5f437084d171160a03aa45085abc3be90d2b1edddbf02bbf27eb9059f16be5c2af6d4ffb816fdfc7b157eb59198e1427 SHA512 76717aec76027abb394db0bc840b97fc7d03a7f1d3e2094c6593dab75d9e2eaca4ca8f7fad9937494ad08c40fe37e503a5a779a04d0d1bc12fcaebfd6256201b +DIST uniffi_core-0.28.1.crate 44316 BLAKE2B b56700df80dda5315dbcd22fb12ce97fcfa38d8f996a3b8651d0c6ace71926eaf70b03fd9723583c1a0e129e156c49a1855e513891ab129858ffb2c534b9ce18 SHA512 baa92c8ad88c093e7838d1e12adc99219b10d40c218ae2d8f4f19c3d1ff05fae2067cd3d155c73fa2d71c5b27be5f59143ddd23cc772f73d3d0bea01009942a9 +DIST uniffi_macros-0.27.0.crate 34883 BLAKE2B 00ae7087a3c7553dc7145d521b5855d6b518451f42cf9fd794948afdadc1795c8ad590c52c7752ef4b75bb261e314cf2b7ff3d8560225d2cede30bb9cb11302c SHA512 9d7a6a419982b2e2508711c38fd65bc7b85a1d94bf8236e06ce1f0c10f3787243427c21086e1501378e44bb39862b722e39ab320861ba75c46aab485f4127dcb +DIST uniffi_macros-0.28.0.crate 37378 BLAKE2B 82aeddedd3dad404a5820e181f71d774a5108f4f1da8d412849cb379c06439c0d3d9aaf76c7d535ccb4de5c0263f513fd4d46e08a453c0df945329ca68a383c0 SHA512 55aaf06b96099f48e00e06c75df89d2263e482ee4cffbf5a8fdd02567615a1e08d086eacbb1b3bcf92063813e2f0d89e0f888650c6d2185ffad1b475a0dc5709 +DIST uniffi_macros-0.28.1.crate 37594 BLAKE2B 5077599cf61de419219f1a07e5da622a3512355214697cf81678a66d84bfc188a88db10f94167e9fdfc3bdab36d5ee06b3104af641e3761d26ce9eb926e2646e SHA512 946af27628c428dd8a37c93a6fb512af7c6196b000a9b04ef32f770f142f20b3020e85535f1f480fe6f51b15fd5555817d3f6646bdcca5df98d4677c4375dba3 +DIST uniffi_meta-0.27.0.crate 14414 BLAKE2B 24ade4086afe91904aaf0ad377c25369a11a9e60a4f25c15f753b797683a4a9ad87f3035ce0e540c947fe5c9163f9dfed258efff9e972d91133af9e28c20ab50 SHA512 1910f4f6eaf8ddda58597ba02bbb1c53e5921dcceec7eb153c2fa92bb99dabc3b6377a1b56bf072e56e5bdd4fb3507f5fad75e0e20b5f48dc63a198da55a449f +DIST uniffi_meta-0.28.0.crate 14621 BLAKE2B 7a0736c6c31097759eb2f8306cde9c0e54765d6115abbbde182c7cf9572c3d70a9d0d6d0c7bd38815c647ee456ba9c4b0deee5971a4019367fffc019e1f02257 SHA512 e90fb97b57137b53be7e5d4865ffd8614907e0a85bf7197065cb17c065f8f687efd3a51476c767732c0d4c7d14e93f79b8bbf1cacae011e76091e086588036f6 +DIST uniffi_meta-0.28.1.crate 14882 BLAKE2B bc3421458bcc8b98dbd86532cca0bc8680864e86cf83415ede95a1346b1591bb80747150a934849747f65f166de9dc6fc773784ed6e5bc07cac8c1e278dad37a SHA512 c12107c9cb3bfcc703304c6cebf0803cf5c47ac37cd170c2e8db9118b2189972b190515e296695ffc26b6c647c15759f0d6688d64822d8f84648c9bf058685fb +DIST uniffi_testing-0.27.0.crate 3510 BLAKE2B c1ebae6bcfb6129ee4ac7be825825a51761224c33fcf47b5876a7a6690dbf176a4113d5002d77702c64f261b0a774153df123db2250c9762821e517f790ef759 SHA512 077eb5d8947f4dfa69a106b22ba329c332ca53d9c3ced64a199055fb4734a5651bff8c9e4e6c7a3420b655c35fc27e4693db72b1a1c7b15d5db123dffe7b1d55 +DIST uniffi_testing-0.28.0.crate 3511 BLAKE2B c085b0881b8ee451fac887402ceaf91987dd3e37a42b1fa22aa5383820b55d7c9ffd9407c3e3cae46e7037fa5fcd2612fd67d00a49521c711c8aff043d57042c SHA512 0a734773276651bd34e2360d27c356acefd69b29299c4e87c68e57413544a49335c67b2330d139eb0b6c87a3e1099cb725ab133ddc72086817f8cc587b092b78 +DIST uniffi_testing-0.28.1.crate 3599 BLAKE2B a2c13937ee50bb57e1feca8a8f50330da45ccd1378707de861e4d0043d611cc7bde63eb6f81f79b3d96a38349c90c503af6f10dac8e94ad5d4ff00445879f96a SHA512 cb52f9714e39db7cbcff8dfa5ad0913a2d9a885987e62a697908703f832cc5e288f4601b58d94af5411e91e0075ad7a935978f0ed41f98e1e0eabd998edf0fc5 +DIST uniffi_udl-0.27.0.crate 21721 BLAKE2B 0d63a2277ca58664fa3a4eaa466f540e3107e1b4657e6f15b3ec37ece0ece1f430796c37050c0f38d22af9f8958b83544ec6b08f1efa7059eda00d520aed8179 SHA512 e3619a371abc04c86185e40acdc772bff03a1a68ea3f4016f60ebb11707b6df484a9d384eab128b348123a1d213088637b632bb47cc0196b824a268b95669cc1 +DIST uniffi_udl-0.28.0.crate 21787 BLAKE2B 45860644d211a27813470552ed64828116e3d4fe55f7bddc1fc995eb894dee0ae5652c22ee0cdd5ba0b804c540f78fed6173177548bb81731cc978539a466298 SHA512 a2556fbf015747b4bd2f3187b62a8f583a63ce19af4e1637527bf46e00005e91965adb36cab69f3d3afe3225abc163d86d8d2b30d936fdf5240539c48ce045fe +DIST uniffi_udl-0.28.1.crate 22367 BLAKE2B 850035ccf158d310f5d48f8a4f4ff5e7b9fc2d1934e800aadd7c47bba3aa2c96a539c8838ddff5db2b5f838eba6053b693940ea268ff0cb5c0c447b7a0dbfea3 SHA512 aa4f120eca3eea71d8a493f8c7c1122923d6e75fe5dbc6f2806d34363a2fc421f84e628d4e8271b64011f3b499cd9c9d84b37db20457ec925724d9e8fefc51df +DIST unindent-0.2.3.crate 7306 BLAKE2B a57407b117e99c230750c7d4a2a0899586c8271e4ba88ecb409c976905c014f42885372c234a75fbfbedf71dbed779f95f735975d150adacdcb61152a49db4c2 SHA512 2f1eb420ea3653b00d3e5fa0c2c105da8fd8a37cb3e699373c168604b799fccd5f0faf0cddce4212d119c2afb0c86b41efc3a50752b83ff7beda2bd84d360505 +DIST unscanny-0.1.0.crate 10338 BLAKE2B fd725928107d4d2ed2686709335ef01136bcd54d34180189906b7c2436e3f77496328484c623dec4920738f4a07e92be7e7581387c4f5b6996fa34c03efd7b0f SHA512 8267e327e4e852d627d416d58ebad5ba937ab6a2477b265fd5f79a98d43ade2d1780e67696b801cae8a4af10da8f7c0c257d2c878289eb6cf7e711dcf357d87c +DIST untrusted-0.9.0.crate 14447 BLAKE2B 8e9c3ae09435af0885bc4a6e3c8943805b48cfc00bdae228c7c43093254e1be15d7005d1026561ff369ec37865d8458203f421a9c89ae3db077f655449621aed SHA512 5929e4079c1c2ff933ae8d8f59a2ecc7a424e71a20d1b8821f75925af68bdf82604b024c008e5464b02e25ff093e561a352b685e755b3d0b27e4c30254689416 +DIST ureq-2.9.6.crate 113677 BLAKE2B a795b9a3b0985daf2bb27e489b32387693bbcaf32a126b083d584693a921c8b3dc900987846209497d468b655d30c9b364112905cbad870c6758aec28a5c3268 SHA512 c2c860006e33146589107aa191552530749c143ab93a60ff3fa959dd53bbd03c48d7f4b410ecc4c92c28c2b483ec3c2c720373a6ee54ef8f9c31b069da205f9e +DIST ureq-2.9.7.crate 113834 BLAKE2B e80ea64d610ab01d129527a120878ac3eb38248885c772aead6fb983f777b7469f7debd042ce93c0bfb6adeeb7ed476f7dd96c62de386ec2d64dbed28973a829 SHA512 33893aa1df316b5987571ce6b46373c625ed89e452a313f9490d63896f144e56ee0c35c1eaec77eb8d2a66e7726f3dae6e96bd2ee0db7c0604485105fc69bef4 +DIST url-2.5.0.crate 78605 BLAKE2B f3fec3477248cbbe67866577eebb03f517c284a5e5cb783132b11ef3ad156a03524f4730f188d822dec85169d7474e265099296d6bdd4adf5ffaa0a118821617 SHA512 4aedbc48b85bcc2853189f5fe8265a01c76516b5507f4e958d8d0b860fe2590c69c95f0f4b9fd6fac9b8d5911bcb0a5e9ab7f8e8b600f37a12db1438976ee5c3 +DIST url-2.5.2.crate 79704 BLAKE2B be3526298a8816fbd88385caf49c2d58aacc7dcbe2d9183478cf501c26fb5f22d7704ef1313ba6d355e849cbf8ab7980310c1aae85e253a2b28d59099e23af29 SHA512 2515903e41c0659cb226f9bb049ef80f2a49d1b609b6ac480e570a84e899088ffe3be4fb58f41a1fa7f5288eb5f97ab513f331aeb6d56979df783d48e2ace28a +DIST urlencoding-2.1.3.crate 6538 BLAKE2B 65777b0990aa6b3d27a47f36114da8622026ac8946b5ffb6e04172b666ec7244a55c250a7fb626472bb2b636eb32ee945599cee5ce7351c3cef2322366db15ff SHA512 035848d9243ed6a4528377b56edd7f8bcb5f824381b420dc8f5c4bfc3f1246655c54eaa7de0e4aaa7138e0b08fd796b9ace140ab919aed2d94f6952b577386ac +DIST utf8parse-0.2.1.crate 13435 BLAKE2B a1c111d7ffc60690f2aaa86f034c66ba1abe4e126f1774a4377d41eba3269369862f57515af387ea785d69a8adf46338b5e53761b5ee6f4f4380473f4d9cab0a SHA512 51fba8f1e7eb74b7020fd831e30a67fc8353ac2ee07335c8c3374a5570ac8117f165f6905d4b7f0360095b7b5ed3e739001d02a8cc3c89195baf2cd679136050 +DIST utf8parse-0.2.2.crate 13499 BLAKE2B 095b5d219ab8ff04c06fd6303e03d913ae36a57845f0b2ca3217a40e31a54cb0fb5ecedbde165d28f5f60f1553d8252986d7098fa83befc84a7cb20bf3b76144 SHA512 f3dbf78fe924f1dc3cf9498b6e43fb10174699463f31091a7a8136d8f31ec84fc00e80e3d8551b7e86257e8b3573cfddb56fc0de797fdb2cde0e962a8f239266 +DIST uuid-1.7.0.crate 42627 BLAKE2B 493f6a3a643d3493a2bd7e0e92a1ccfb7bd722e3a1fc8deb7df0ddc875a822daead1cdd35dc3ac6f26346844100a671318d71e5ad760c9587471d4f05bbb0c69 SHA512 2ea704d082b725d98717d772e1af84fe743929ee32658ebeb111c6fa2395ff5f44558b7e375087617f91c6f7bc242f2db96e80a631071722de6fe15af845e856 +DIST uuid-1.8.0.crate 44043 BLAKE2B 6a5e3008f0399d5606ea4ef51e5932aedf2a02e747b9bee4b4c2c6646cd959a720373c346a734c00554ff0359fe42bdf471dea5029e23a9e70164e20895cacee SHA512 fe254f0bf6b863538ce568405569a4c755b33bce561148661b10985bf4485fa7ee7a6ec650d93656552b3cdead46b2074ebfd45b040edef19cd1648300f68ed5 +DIST valuable-0.1.0.crate 27718 BLAKE2B ef5ded994c9a6dd302bed27f0d757447b0c86dfefa499c1ef0d25c3a6745ce61cfa2c926826534c9f605f9b89b4a19f91f06f94ae7c03f1ddc4c58fab3ae58bb SHA512 a97f65db1f1c5049a276dbb0e45e25c6fc6ce9d27ac1fcd77c945324cd8216ef60344065c79799ca04e338455e4f7422c44078eea32d5fc359dd0211ee7eb387 +DIST vcpkg-0.2.15.crate 228735 BLAKE2B 6b6bacd9a7fa38919241f45a97f58cae957e58d3aac99df208a26aa718e4f1644f4ccefa31b09151e5c1952288e0e5837c363918b98c7f55079a948a952c1c50 SHA512 7322a21e8811b2fe4e79e09dc321458068ecdf1953f05d36233f3278ecc0b1dfc64194db7010dd46fcf692285f42475beb090c6c6cac0c8f9fe0eb5c770e3172 +DIST version_check-0.9.4.crate 14895 BLAKE2B fa1fa4008af165bfc1fdbe560488afd9d232cfafee94104fbcc4cbc52f234849bff9ddfa88109a1ac682f6d9c1d86b0459893d223f64e65adc08966aaf93dc89 SHA512 b172dc9a3759a4a683ffc39b9a40b03b9974b626a088217de87090466cef695226557c226cf3e469b2b25ee7297b7eb0d7719878cab42457f80146a81943c0c8 +DIST version_check-0.9.5.crate 15554 BLAKE2B 131e75cc287518831e142430e2a39b48e4275874f4473780d47a27552294097aa1cddb65c385583e1022478f940b495eb43c24a8b1617b8ac5a24af3340c0d72 SHA512 d11d5a2240ab0c67ea69db56561ce202201edeef9a8e5eda3d9ae7ab7bb5752d8f343fe7f6536d8383de8d55f9024efa84f66a0c21e69563b7a38c4a628014db +DIST versions-5.0.1.crate 15850 BLAKE2B bad495d74d67d1dc60e2b3d62ed765ade0dae63e99a10b9f28c456deea555ff20e2a28ab28730ee5150266757da54cb3f237506ccdf4ca960f2c89a8a8035e1c SHA512 2b2c4b60b53b7b4e6f69a36a798f74353fe75b952dad5d3fc3f83ac353ad5545332f34d81cb43fef48020dd6e8e0ff4c0fd8b69e262d67ba38e80c1311fff5ab +DIST versions-6.2.0.crate 19968 BLAKE2B 5e4129f4acb53b21aebcfafbc568425aa6d004deefc1f3a22b6aa56349852bf8a88ff0ae2db4c39554405099b705d61f7041f216928269f62cf7db7d71b14ecb SHA512 c1289b03f5b453c3298ef74b34b6a2f5fc392f2791763c711ae9d2abab74e904906d40d7f2da45c371c66fac93e6334accba1298e2567afb3f9a73ec8b037c31 +DIST wait-timeout-0.2.0.crate 12441 BLAKE2B a99d3f57bc6e784ac06167f98b2dc2841f730dfab4fb9772b15e67707f756d6ba7daeb3e992d32291bed3daa85eaa8a8ddde64db5e1acf1cc4031fc9bdc82212 SHA512 db3b7aa2acfd44e64451042b8ba98eecab77a82aa5c58ed08dadb119ab36dee4e26d62baad7978ed56d5ad03019c96be5021455362290f56043981137bac8066 +DIST walkdir-2.4.0.crate 23550 BLAKE2B b4298c01cb38be0479b7ddfee627af01f889b6b6ff432e368bb67f65134c3958a4fe271a5a7dd61b19259ae88f5680e5ce8e12e50a872b05fcba68f59b7073ec SHA512 09e1bc852c01b452c95b26a369831a97bc5c9e0ada3111c73774570dd73bb5b9e4735317d5572304fb48dca44ce7b9f77bbd17c418b6b047b2ab17b8bb42d9d9 +DIST walkdir-2.5.0.crate 23951 BLAKE2B a2d3a973f206e94699adec0263dd5e211347722cf3ab82536295019268b3125084da5dbcad818070bfdcb6a5de08da4eb483475bc225a829f58a1e3e040b5fba SHA512 da36a121dc6656942dc9cd9887fcf4f6eea7750354ef3f59c7c25d836e7afe06f33260b4d55d0d99421104ed4ce56ef2a1f0f4c3b713766fff90548c21793fad +DIST wasi-0.11.0+wasi-snapshot-preview1.crate 28131 BLAKE2B fe501889f25d65e2d032f885cc50c4f8bf7dd70fd5cbc438de349838370d8699e9627b0a4fc76030ea9fe6d508f41d0c9928a875fdbc47e73bfb17241cf7b155 SHA512 043500ab28cd9cb779475255da5d109ebab7fccca72b64873dc28d77bc5a157ba8d96b9e8f05223b5b36c7089bb7b4ba87657fc69bac16b78972f897294a865f +DIST webpki-roots-0.26.0.crate 251778 BLAKE2B ca16fd806c1904a91aa0a3758c0cc96600877c3ed50680f57d85b3fd6b0336b02a70c1e582bc05ea768519bb1459bf642f99ba660ad41e1c9289fda45dafa1c2 SHA512 56b21f5be94d9e34b50f01a4baa647f3d2ecd60a61b8a97edb45d625d0393a4460bcde29b889bdb52c3f44bf3f25ee875730e133c21a65fea68b1b3d106d0a77 +DIST webpki-roots-0.26.2.crate 250806 BLAKE2B 7b236f9131044d53eeaa1b3b3cb8937c52ec9bb60b18a49500cd5a7a5b093a30dc8b7a92a697fe60a1bdba9c11fa59b7f593ada683ab32c0a0de28a2a0132ec1 SHA512 393869b21ed8afbd17a5764395c803dc896c696419c06cb2de4ccb2480ebbaa3219a00cd98b714e123b53497338b01698c956bcfe5c22a833ba5f889d384f467 +DIST weedle2-5.0.0.crate 17777 BLAKE2B f31cf97f698008ac978a93dbd746c9094bd726bf976a9a68d6702c31b11d5cd3dce148d4cda1a5dbbc0ffce3c3704444e81e691880347021a575530142e1aa1a SHA512 29d722cd3d210dcfdaecc4f430cb115ec3a73cccfb860c98f784b4ef91b07bb33ebc02a7a31f67fb13c9bfff836cf85f183a5f24fb60d963607738c386fbc4c0 +DIST which-5.0.0.crate 16635 BLAKE2B 5319f2effea2b86ed865be31efbb66035670cb80245f212268a9d3b4798b97fb658ef02b4db3ba85aaf82007e0498e98f35f67128bd9a6796accbbb37161fadd SHA512 cf2b6ec2f156f4d6af0bdb8b468965784000158bc7ab8f76fa1b1d7a1a2c732a7392c8ea09d3cc79259411e3ed7ed2d448a6aa94fe7c2fae077186086b0f826a +DIST which-6.0.0.crate 16751 BLAKE2B f681600f2e2af626273e4b189d43dee9ca5c09f1808870c49aa0974d56ea1f944e83a0078656ef519d6c172c0b22a56f5d0adba21ef640afb2665bf9b58a0d54 SHA512 f0da2731701a33a07704672490e53e3b1476f3b06856e7b9e00aecf92dde5b6ae13199780ffe202a19205cc61ba1eeacd519f6a132307d8d2d07d0577cb73b50 +DIST which-6.0.1.crate 16542 BLAKE2B 20fc6e56405a9774569f315703b2d8f20029c225e7839ad620121aca7e1e0ee3a0295e402b6a0f504d18774f3266b98b56ffcafbda153321b1947f44205ae51e SHA512 6a80b7bf46a7fde1fd4ec6cddb7bafdf9b9878a493fc5fb6ed425827206100bb45850541b42113be43aa7b336a30f98e14a5fa20d09a6411e3f420b96f7273af +DIST which-6.0.3.crate 16937 BLAKE2B c4916ce80625b8b869cbf43844d689c62545964cb60f9741851393540a241d1d440dd64517949f3a64a4e9256584393fff84e3cea5f75773c9afd8b7ef580333 SHA512 82048af7dee4bd274f977530a19c2e2c86ac12936b7d814b2a86f13b2063e1a3d7092846d1ab66e3f653bf7ebbf5eae8bbce061a970c5ddb30b151234dd0593d +DIST wild-2.2.1.crate 8080 BLAKE2B 489a2a625aa8091fdef9f4d49747db7816d82c01384672bd12ff9e4c906f3418fa5a5fa8951b625f6d22a9c1977c523f1b54d7c4252c241413ef6f63d327cb29 SHA512 8f92b83cb2568fed7841ad372111138d9ea5806c21a0affaecc639f0556ab879ca42fe205fe3c1e55a1b5c1c4fb0b705a5566b06bad5c119a1d41df9c01ed2c9 +DIST winapi-0.3.9.crate 1200382 BLAKE2B cb5799749ccd935ea2d7068d953cecf19f543d9db7dc16ad4584bb7005373ada34937a3ced7225544d8bc765da599911c7a3190efefb3a25b7c1bb7123b4f673 SHA512 ff8b7b78065f3d8999ec03c725a0460ebc059771bf071c7a3df3f0ecd733edf3b0a2450024d4e24e1aedddaecd9038ce1376c0d8bbf45132068cf45cf4a53a97 +DIST winapi-i686-pc-windows-gnu-0.4.0.crate 2918815 BLAKE2B 4d357e4d30f9552972170d65b9a5358b69c46a3e772fe05efc22f3d4ffc1caeeaad7aacdc7abd503a7ad0545f8bd7d22bf351dcb6df76f812fa4d45c34d65df0 SHA512 a672ccefd0730a8166fef1d4e39f9034d9ae426a3f5e28d1f4169fa5c5790767693f281d890e7804773b34acdb0ae1febac33cde8c50c0044a5a6152c7209ec2 +DIST winapi-util-0.1.6.crate 12234 BLAKE2B b8db8ec9d7ada5532a22a2d070320174c32ece1f48890e9b028708e194fe72a04287b11910dc2ddc7f9c9674a9d8d39449b3e100725e1f59e59e3047a7e3650b SHA512 b1c949f9bcd34c1949a9d3a7bde6ce62fcf3d2cb66df60af41fe67a9d1acb24e571cdd5ac721be9f1ee4b3af5ef5149b5724ad6e02b558e124ef2a4412d12db9 +DIST winapi-util-0.1.8.crate 12416 BLAKE2B 5b48c27dfbb5db5c332f7e248138327b35ceec0909788b940168e7f6fe1402800da5e7690b2b1654da6c510b5c720330a92da16dff53ef15821f37fef6f335e3 SHA512 e186111398f9f0f0686e791ad0d72c39205e5f246b6e020df413e477ee07f32e91d09405c61dc92752f061f54fd7533435545c1a151477b40e2d68acc94a57fd +DIST winapi-x86_64-pc-windows-gnu-0.4.0.crate 2947998 BLAKE2B 2ad1ea8b5fa07d544e910ccba043ae925269b76b26c9da356305b34b86741dd8b9aff0b9ffe3d562db4fcd7d7c46a11ce9e3168b782b1d89ae6881742b7ede82 SHA512 4a654af6a5d649dc87e00497245096b35a2894ae66f155cb62389902c3b93ddcc5cf7d0d8b9dd97b291d2d80bc686af2298e80abef6ac69883f4a54e79712513 +DIST windows-sys-0.36.1.crate 3347053 BLAKE2B 818f7812bd9a55a4e95b3d461fa5fcc14569a159882f950d20fd5a6b7d2a2841f082c0bccaab657f5830549e6286a37d9f8fdf825a42403f543b51e35b2d20d4 SHA512 80973e461bef3be0d0d0c13d02b2129aeb0d0700768d637544315654126f101b39f980738035fe325bd96f549493a2245bd7b82511f833efa7bbcb2f62266001 +DIST windows-sys-0.48.0.crate 2628884 BLAKE2B 551e900de4f67187ef034b60df9fd0e0d8f82a3100ef28e1eabd543ac129d882dc86ffcc1714071aba09e4cb2ae2d2f07ace1a32b99fd989ce525cf05991edab SHA512 bdf534bcf3face31e9ebe11427a911a53f89f4ff5eaea8cccd094e139bfe14b2aec602b1cab1df774794d999477439d9adc6b627a8e33c20334fc348ba2c47ed +DIST windows-sys-0.52.0.crate 2576877 BLAKE2B 69d6b560ccfc8f679e2678663ba606060d71fa28efa82c8aef8cceaa2c63b06f2052764d60163964f939649a26bbec6361ee4b094555e941fae92070db566980 SHA512 24ee0df246c2b456a4987a9124786a28acd358768cc7d1305bccd81bc5bb8822b81a03fb18d35174a520b911c6d9b685f81a34ab319fee13da3b985273584f03 +DIST windows-targets-0.48.1.crate 6902 BLAKE2B 8e6cd47dea52131c66983cbf4982e88f7bd30416dfae4e380f7afb39f67ee0ac88d40769668dd5aba40d4415f9f00cbc2ac98d598506fed26029f5ec4df3a2c5 SHA512 e48179620cce528292167f1d5ee2deea0659569c996dc90eb4ab62b9ea8baee6c0bea3ab739e06d8793c9690bfc895545ed0039cb633ca39293de79c42ea9de2 +DIST windows-targets-0.48.5.crate 6904 BLAKE2B 7396bb210f37bd51da86f39fca3425c8f6610721d5c4e94f9fafa0a8a8046303b3fcc6979146bcfaa32f4406d242a0455f6cbb220f84c6ff84650e755acf5223 SHA512 e079eeef255a046be7f8e6a31c14f7b230254ebcf05eed2944827bb3d2a0dc30940d87593cf544d5e7ef35f6312b99430efcfb01421d91b02bb9c4bef7d98709 +DIST windows-targets-0.52.0.crate 6229 BLAKE2B 4b1efdd32202f112d3782b586ce60667f5d3b6f97ccae0d7da833aee2ae81ceece88b5ef4126db2448c9019de3f77e4fe66ed4286bb6275d9a5e8ab74725b804 SHA512 0ea09552d89b802ec0d419b640fa02d0af7af602704a0e88ba10f81d123dee0c907460f6ec91224177ec9a948970abd7414740eb219148a4d66c269c2362740e +DIST windows-targets-0.52.5.crate 6376 BLAKE2B 1d39fd86380ab086c536d88e67b60956410b345790ccea62a25e6a700757b2a9cfa6dfeb7b86934cf47b981ea2e5f42dddf49780ad9829a551dc507fcf108641 SHA512 d00d7bc7eec3c10272e803ee5c9ea0d9b07c43311124dae975b4f5aae7408c5f2ccb2fe6e68228ea3d4e70b6b658382cac6992ea177f43a9cba2ef95c4fda0ee +DIST windows-targets-0.52.6.crate 6403 BLAKE2B eb98d0a8daeed5fe76e7fa8edb2743e2a3e77dfb9c4ea68605a6ab10532cb7cfc43bc1cea0180869445bd940be762a40136500e26b84ca88b5e0c502004c7a4c SHA512 d6d2dbd96096c6c396dba141a9817e377c35877f3b2fe58b2553280c7cfcb1ed6ee75bd4d62c9b882662de67ddaf0c1049b91530d29c94dd709c230e08eb895f +DIST windows_aarch64_gnullvm-0.48.0.crate 366543 BLAKE2B 9b10f65089fe6da3ff38a1061783f635644ae84f567f891eaced280af68f7ff3919b34289e8850aa34554bb0346903273ff0a7fa743ca8794c2d23a9f1b0185f SHA512 80c5aa74c5669f7acff3882a8e7575f15e8d7cc58c11a1cb731ff423eb9cc9ba43cc6b80e52803c0d44e6a9001655ba87de6f43a9fe858da6d6e3a5c983a2711 +DIST windows_aarch64_gnullvm-0.48.5.crate 418492 BLAKE2B 5c6f7d73ad05740f0bac304ed1ef9b2ea63b0d6ca8f875552ae299a0b73b1557e8fe996f1c2b69be9f2df350c9288690f49ee62239a2896991364331d6c55462 SHA512 20158d31454488f6053d3ad7b97d7fc6eae6cf37e4ba0e50c28bd29b368505eed64199ae31104d5f97b66846be54e5ed25c0ad31ea850819205c573a31ac0996 +DIST windows_aarch64_gnullvm-0.52.0.crate 430182 BLAKE2B f23370c62c4ab3fd885e3ee22e8ec2fb5a3a837a57044c1df3f9986dd4e7e9d0a44ec58be1648a41e1ea4d037afa3077f0f03de0204199a82fb8395731815a4a SHA512 b7c3fe0a2ad5149be0df48fc7a4d15879eb130bd9441c58c25fc71b8a91483f0b553fb1bf29a9302acd348e9083a547430a840b059b0cfe19867ecaffcae986f +DIST windows_aarch64_gnullvm-0.52.5.crate 433266 BLAKE2B dee1b69cdf1fbd4143136909e4df3adaa7b80d7630a01ca9a42fc5ad0d5a4d9a9e2873b43c6d8e55de59f237d9199fad0768c4e1cda3b1e5354847bd70d4c79e SHA512 b4cf511025458fe30d5b11368af285610e1654a8986ea9f78fa81b8bb87d38a00c4869441c62692534df66d06baf14c8a4d17f8eb06468eb260b99e2fda6439d +DIST windows_aarch64_gnullvm-0.52.6.crate 435718 BLAKE2B 8b12ae02892cb69401329034bbca671d13bd268a112120b56b90504707cef89decfbd2560492844a9f0588fab62dc1476ab7e931126b939015d25a8cc91ca334 SHA512 f62b2d942bdb3a9353465b07d47b93de179bb706511aa497e4addd74cff95e689a9b633e7801ce786e73b5ae5f30b506b6faa199c5ab86eefdc1d94652df79c5 +DIST windows_aarch64_msvc-0.36.1.crate 661960 BLAKE2B d503150a05c4aa6ec376d1094ad24a7a4b3579d8f60cae65f4a98adfe830dd776c8996d5c3acfbfca1a69598475b918b5de2a162e3253b0b28cd6aa17de2dc13 SHA512 d0c352c78caec9c71bbaa1a688baab8f39a33c903c0492b19398c76e08194183e254ecd3a8b24af3e7e5e1d9d97373dcbab54499236829898a4fd153cfde2ccf +DIST windows_aarch64_msvc-0.48.0.crate 671479 BLAKE2B 0c80f210437628e1d878d1d14e884fea532c7539b3030aa76d46f27d02372c715c6e33d7efdbbd770666472b44a66c30711a33d819ede9cdcd51c96355802d45 SHA512 617e47a7202f1db4dbd3ecea509682135ccd85e3a458c0331b9bc7aa1d84e5756b59c881cb098d5c6d4c951248d13c8253a8e8a50938e1997bd19ceba77262df +DIST windows_aarch64_msvc-0.48.5.crate 798483 BLAKE2B 60c466d6536426425a34b5ca20da97c8127ebeb4fb9b1363911165bada484f8913fcd50e90410b5661e0c27dbfe8f4eeaa62fb17d1f3566bfc82b6255e11619b SHA512 223f016c6f1a44dbc5c8a8428b39438f75380ea06951b7c26ed0877b19d79410c6fde5e4c7f2c839b6e76159131f39a1230e0e3a208dfc425ba9117e3665c4ff +DIST windows_aarch64_msvc-0.52.0.crate 821663 BLAKE2B e6f772858205f7cd871722136aec4d00daea4793ff9dcae53e6311e74526c46aa11c2b3df7a85e6c577757254cbfa5a713e68c694625ca274b64e7a1c5532c23 SHA512 8446bfe5b9fe538415762c8129ab3bf2fe45482e045bce367475747786602ad4ae1187c6e508dd9d7b6be81bfc8d430e0db9c624e35c7cc52e823023e46f5cf1 +DIST windows_aarch64_msvc-0.52.5.crate 827944 BLAKE2B 3bcb16d527be1dfdf18a9105ab259a064f00e949937ca423c8dcd1d2b90090d85aa7e42ca6ccc50c9baeee1aa144123d0a04643f9ff1147e62b2fce28b8a697b SHA512 c8974f81e37a43d92c4a8b142705e36b7acc58d9150d80ffa3997433da878044c467a2d9167ba792d37a183a0082d912500fea8c8fed743f395b63ca62a5758d +DIST windows_aarch64_msvc-0.52.6.crate 832615 BLAKE2B adc8ff61b6dc96d39c92c7d4221ae6aa0575edfc016cfcd046067ca5d8fcfd56d10e8e227be1c038ce34684be22c7ccaf5f18cd5a7638d28fbff4ba15b48b90b SHA512 a3e21305ad0e6de38f5b5ed5d37ee5825b7521064163bcdf31d63341cd87983f54377865d2daf3bb480d2d0aa66d6f598fa09540ec1d71baea74569c86bd213b +DIST windows_i686_gnu-0.36.1.crate 818115 BLAKE2B fdb78cf88e1049d1ed6c474f870dfd1ff37b48bc24726d754cfec5b3e77075162f291f93aa709c07c9fa38ccb21a6c31cb5149dabc2cc8ad8a85c03408384a0b SHA512 e2c60e6639beb879472a06ed4462667eb4a78385df6bcde1ca579af759cf2b4ac70e84f7dd7b736e7fbd1b129061555671fed4b83bcd81a6083cc013963194a5 +DIST windows_i686_gnu-0.48.0.crate 741490 BLAKE2B 5a4a584f8d8ee5bbd2d4c5b6749a66f2d43fc9e4ef90faab2227709b270f0d46fc26578c029edd96877c71309316ddb32d91c39f46d88f9a484c614f866e3dbe SHA512 15149fdd48b61b6d993acd392dbd353d0280d984ea88745217e4207937174bb90cdd9701f69ff0fe06a842f03607cbb57937d20d79ab577181e605a8a8fadc68 +DIST windows_i686_gnu-0.48.5.crate 844891 BLAKE2B fdc37cd74a4982056bf22fdb7b84e1c55dc838f3cb19ff3648730a77e673ef4ecc0380b3e4277bb8df2fcfa25f57b69014713d9e3ed27c28e19b25b3ea2ab774 SHA512 931ba5c1e4eb8ae73248e00d9611298d1c4b4b0dae719fdeb9243930cd420a103a7bc2738e0a4887c42c8f25728d6c5d64ad141dc092bc3f1d0f35dbe37d303a +DIST windows_i686_gnu-0.52.0.crate 870285 BLAKE2B a7688062a128a1b1394b3978210334e4e2aaa10dce131457c4a11ce0cb3f551e7f4962d1ece1846d8e9526983ced0e0a3ee8c933858e9314b62e76381e086ef9 SHA512 fe993f5bb6e039c257be9b35337e0221f718d23866818bfd19c76aaae236aafc2de4bb5014fcdf919563b5901cdaa14a2136cd086eeed3c83e46a5d02f6aa77e +DIST windows_i686_gnu-0.52.5.crate 875699 BLAKE2B 528ea431d080c5326e4c6ed316d9ea3e38b40c2e1322a12a432506a2c11555a94537661a0941e90c20eff4a9ce42c12539876dae6e77a1df18b522529928b309 SHA512 cc3e0362fb62dd5e8a855bda3be0177708ec8629ee9685f1f9aaac3f71a8cb082387388bdf49b09d3f5ee24a636b0b4f933d2c8bb75db434ee0192c8ce0547d2 +DIST windows_i686_gnu-0.52.6.crate 880402 BLAKE2B 5aab8ee07132eccb7695807eb44811beeb0657aadfb672c54e99b6ae39c067ba9b93e38fc69bb5b9b14a9759f263ccd5e301597d2727d83b31b49a409b6bd405 SHA512 a1f6b5dd23d17ec3567bc9d11a4be6f35e196eee21ca342e9b88dbaa6a5f7c46e439c834b77e724f32ac22c0d81573746b3b513a6c944a221b92b2c76fe98822 +DIST windows_i686_gnullvm-0.52.5.crate 473064 BLAKE2B abe41ee330c05ee1366b3a835d15c6db3964ffd7b340ee69d215056b0d4b65c67f2782b0c04a55db64001098de87c93e2d447e25ef2a27f2cfa6685b8cf20c88 SHA512 da45c882248070911bf55698f62c245cb081a23254cdcf578df053905adb9117454235e52dcf1dd97c0d2248f92ff1d2fd3e18844a7be8d93ba08590c1eca22b +DIST windows_i686_gnullvm-0.52.6.crate 475940 BLAKE2B fec4fda8bb2bf319a501a22372fa642ae682e4dee3235b258a028190ee73220bfc55b3142f06249bb4579b17e5fde662bb2b121aefe18544653350d7d0fe7d8e SHA512 95f13af855d530acc0b856214478d4b11b8dbab3f8f79dd223d0b009790c0e46d096fc1773e0277997deb2d5b96c704f17f23c7df11411524629f75415dec99f +DIST windows_i686_msvc-0.36.1.crate 724575 BLAKE2B cf964bec007d8432e2009644cf7f89ea7d910ccf9512c067b7bf5c6c825208ce4a36e9864c0cbca137f523983eb46e58e4bd01054cecd7ac7126d2ba9f67ac0c SHA512 02bb1507981229422498ce29f6c777d5e412358040128f84b09d948ccddf0461b078a0a20cc7f6ab7da8595121bb369453ae9ea1f0506aab715662e8c631e737 +DIST windows_i686_msvc-0.48.0.crate 730056 BLAKE2B 4e4ad6ed94948145199c2ed50fc65e4af08455a0fd058bb0f763d481f30b029f99a2b8dbac087b29e762500a19270f6683baf62ba99d141eb002a5b0b5c8ea05 SHA512 11a50800e709712dbea907275bc0faa46d2eb2969118445ed5b932d9c5957a09592a5b26a40e554c1f5fd56c6d074a07637e6f88eedd2224e1001e62df7b469b +DIST windows_i686_msvc-0.48.5.crate 864300 BLAKE2B 3d3ea8be55e2d6ced0eeda18abe1dffb925a1a78f456d683e4450d9f2fd287ad2e8494d65b2b770c677a12b3a60d10f0435e16c61880e3867c3657fd44892442 SHA512 70e2fb4fdb006a4cbd43ab2c7e940b277a15fb1790dfa2d1fc1f1fd18bead4886f6dc046e44326603e4894d988578917b8932aba5d9a6a4cc8424911cad9dc7e +DIST windows_i686_msvc-0.52.0.crate 888693 BLAKE2B 7a6e9d03e503c8f543e80a8c7bcf3f50cfa7eed462e487ae7b581746d7cc4d871b33e307110d3a3a75226d88e837f9452ac56bf3baf71b66cfab2626cc15558a SHA512 817ac796fd00bed51d80133ec873cf3d3d582ba41fec8a6f6407fbd7544f198e928aa5d710f70c13bbf74a1dde4c91c54e65eb9d3b7518a7f011ea42725eb671 +DIST windows_i686_msvc-0.52.5.crate 895404 BLAKE2B 02555169f8c5b944231a877de8693fc871ea0d7d33f52f60e164bacb35cec13d463af07c57fec4667948047cc222d8bda7f6a0be01a07e7184b69e4adc2b4577 SHA512 08c96f8e9385ac121549bae8ed228741b32004be20b2955d163a98d4b62af464f1682cb813681fa22823d20646f19335cf0a66203a876b105e119e05a4db0634 +DIST windows_i686_msvc-0.52.6.crate 901163 BLAKE2B 99ed34e052db5ba77bab240ed5d38ce450be347a794d63ec39b719304c32722c9999b540ab40abe0216318900b7412970df99dfb36d1516a9517cae0c77d1bdc SHA512 ca97913ce202d73266cf55947b868bea7e964a4516b6a096a81aeab6a60ee73867171032ced35e3afccff741ddfb2def7468343b6eceb95253e4d4f349efbf96 +DIST windows_x86_64_gnu-0.36.1.crate 790934 BLAKE2B 9dec5d966bdc89efbc81989acca242d519f51676ec37487df2bfacd6bfbc5a8de2871be72c5b96a073a899c666e3a39aa60d493e7df39fa90efe869fb744a332 SHA512 598b69e4f2cd3d68f910d526a66dadb465ff30a8c261c9a4455aa1c5b952d23c04f8edaa063cd16fb43564c116a13f06d607f3a0a9c7495054b8bfe1c04d1865 +DIST windows_x86_64_gnu-0.48.0.crate 703595 BLAKE2B b227efb78a99c43d0538cceadada3fa1840df29adc665787fdcf845b73e77d782da8a9f9aa602e1da61401b550d0107176feb6c397c922a6240b38cc8f04a180 SHA512 38eff1164fb37dbd2bbe53404b20cba92de84cbbd5e4eb9ad60d51fb43d6fdb8b87a1488e2c88ebd4b3ff3b708f93fdc05df4b14a285d3ff11c33ff0d9828602 +DIST windows_x86_64_gnu-0.48.5.crate 801619 BLAKE2B aa7e7e6a6ff9f9553ada3a0a39a9aa798e9d995a8eef36e0b6fdb2a0db93ddecee5548970575271fe43aec74797a420d0ee231d503b5bad1bd999059261e0e33 SHA512 1d6056fae430b3d042bdff3c6217c76be4b8b9f5dada9bad06beaac2db7d7ab9b0a82e44f498ec88e61afa73e99f56d84d445dc3847732b9ce5d947e08485f74 +DIST windows_x86_64_gnu-0.52.0.crate 826213 BLAKE2B 3ca03285ef289fc844261142154e710e996c29940b1c0a7dc3016906ff6452fa50b24f8668fce0ca44bf169ab1228c217fece9f7bddac9ab8bdc54fddafaf8a8 SHA512 2d81af56ad0bc9536f6e066776642a546ce6c6d99551edc0603ffcafe6db15d5d5a32a642b204bbfadf34231daa3894ad7897a9c0c575c2b6bc1e3e58a9a3eb7 +DIST windows_x86_64_gnu-0.52.5.crate 831539 BLAKE2B 54f84c19988addeb7cbbbddb940e430e7345944589419592b99addf9b83bf6d801b18f4e80399b85bbb0b0ccf4608e36d9a50b79d8b1d6ce2b93745856e06eba SHA512 d9bf91765d02d2727344e42081f4bcfa73be97991495126f7e633f27e56a261ada3a8b865a559cfe71f9bc9aed5b14504f89138796766937b3521009726dfab8 +DIST windows_x86_64_gnu-0.52.6.crate 836363 BLAKE2B e2335829155cdbd4a55cc9f9babc237e14e32aab97f6f91afabcdf80d2aee37d6fb4b8669aaf433ff532c85dba59b3d366c7d41b61a2f29b96f960169c900687 SHA512 c4086bb0280042f2bef9b556283b67f8a5cacddd209e1c5fabec63decec6d4fd2d6a7071407973981b98ae0c0cf7034fc612f9e70dc6d3eed9acdec771ae31cb +DIST windows_x86_64_gnullvm-0.48.0.crate 366536 BLAKE2B 295dc3aef18c604d1579978045f4058b1a315083a8ab842bddf5800ec3460b1530ad88c3464acab712a229290aca235810de8a3b6a253859a354d9fa97277e58 SHA512 8d82fad4c8445030844708aa026a62f1ca43362b8e15f14b0d226c7e9cda04ffa0715087b6a025dbb738e8891de24fcc4a2df071a532917cf03c4a46f934f396 +DIST windows_x86_64_gnullvm-0.48.5.crate 418486 BLAKE2B 12a2199d434617c1df1a839e9f435620ad64b40c579f6d0c3677553ad7a48e5765d12c266b04946402e15c92cff2e4ac4979ce2130750ef426e2672119680284 SHA512 c016d5b5e73832b61ff67929d92fa8c16e154656294357266ad29ce1f44db4ca2d2935dba31a6b571187dc838b1d22f1e3b41fefffd1d719a338439adf1646aa +DIST windows_x86_64_gnullvm-0.52.0.crate 430165 BLAKE2B af9345a1f6e0ed1392ca1534c68d23f3be0fbb6a42b3c5518cee14373e645038526da15e849d14abe45c53766a30c6c2042a626482ba4a05409f325eb6aa36b1 SHA512 e88af35fd1c694dc189783e5c81aafa61aeffbddce4d7130e1125d0ce3d932fafeb345990ffd98477c41b578b7f5090f4f9c0457b02146309b95549c9f8f44f0 +DIST windows_x86_64_gnullvm-0.52.5.crate 433246 BLAKE2B f34328a6d100e092ecb34a6305daedf4fecd71840432f104e8707f049b60d784584ce4f02fabdd0281fdb8bc7ebed34b38fdacf3be9c8abd60084e9a4ee9fd56 SHA512 22a978c40df9705cd94e4c52f2b706e477e667b564c608d0adb144b38cb486c279c09d1eb1dd2d6c7bd3401b75a2dc5eafe0f7d642ffe6453f394d1f59483a08 +DIST windows_x86_64_gnullvm-0.52.6.crate 435707 BLAKE2B ab77dccd06328cdb00175f41cdbc120594050a9678b7f9820444391fb50aada3911a91ea00f3a6db2b4fa1820fd23bc9a007dfbe65ad41417c26ee1137ef9b96 SHA512 67681f5859e249c56b0183181811f6212cc7008d6471dad78aecc7ebe3d027686b19210b8aa9014c554410f69f913d21ce2aca928eea905eab779bea26464cbd +DIST windows_x86_64_msvc-0.36.1.crate 661999 BLAKE2B 4cf967f10d4ce148bac967598168752d1996b4ddf5278a8fca53360566c37c1a014bfb4dfdc0ae2d96e01196c42eb4906ea80d8e9dd23b9e9f3163631c9e253e SHA512 89c22ed51a74f531662d80ae0fa5e0215728db1e6caf3c13eaeba95a93548b43c00b8474f52553ac866ac83c203b6c22dc44fbc870e882a4c9c97ba54b87c631 +DIST windows_x86_64_msvc-0.48.0.crate 671422 BLAKE2B abb063610dcc38581657133182b7d9efeed5553df67bd2bd6f30f1668a645186e4824f9ef556a5abc84ace10b1b437b6325bbda6df5a64ce880d7dcb743ac786 SHA512 6e598b8e3ac54912a8ebac01b0dd2c58fd282072527d7fedc7f6ebecdfb7dcb09ae46c22293bc0117849437f8b053db5e90406e7a38276f0f0afd06be3966795 +DIST windows_x86_64_msvc-0.48.5.crate 798412 BLAKE2B 8abc0721e2fb337fe17c91d278947d36122d9045b839ba0cf3e690202d242265b676f23cc301da5f9d98c56ca4ecb76f7d6f072ee71bf986a1deca87020b90e5 SHA512 fa1c5cd14ca2ff0082e2504cf59d317dc4dc6f7138d35c12f95d4476a9c13d8b7f5537d0ee251eee7c99411ad31b22263171b7fbd391daa5d3ea3488ceaa61a0 +DIST windows_x86_64_msvc-0.52.0.crate 821600 BLAKE2B cc448b65f98fc0fc4949ae622b7020d2dae927ae45310649f6ef71809740eda9d3db0fc035676c201fd9ab9639e9e7f21e2e992b4c789542f12b419d2c752179 SHA512 3aaee31533a1a48a6ab5cd15b3cadfbd906a93a153e53919d0aa74e440d11e29830554e4e014c215f5b88a475bb733fa8ba4ce9d773d3e23a40ea9ad37ddd0a7 +DIST windows_x86_64_msvc-0.52.5.crate 827905 BLAKE2B fd5dac198bfbf29878cb461a7338c289c9af16ea80b3e5fa567980d2a6a5ea6a1cd83729ce6fd67e4da171873083dbeb1d6e16a287620f0245201f9cb29c29b4 SHA512 81176090dc725d7fe3867e6322fdc4a4065168580847b35e6f8da345f685c4f66a81e35cd1880dbaabdd4cdc82446dde9d6a0e583cf0b7fe47dda8bc8002f1c6 +DIST windows_x86_64_msvc-0.52.6.crate 832564 BLAKE2B 8e9a3044654c6de99a9153e7cacd575474e7a8a3d883c67b02132af5d3fc99d03cd5f7a4dd666a3947451d11218e6acc6eb5e2526f012481106cc13453839719 SHA512 21944cd8e3a481b514509e73ae3f62722fe7ed380d37ea0c25f8fbdeba79174dd52ff65d898838da5df4197894b74e00f45d47489418e978753b4e55c7e623e7 +DIST winnow-0.5.40.crate 159316 BLAKE2B aae5076d59b3459c901d918d8aaa97ba8bfcc993b8484344f52e45f1f37deb96d6cd3a1663a67f3c367be2b05d633286f270274c621bda9f3ab72b98bb652cc2 SHA512 525156f08514b0110697360be6e331a68d08f0cb65ee4ba3ac9d101dd2d42a8c89601e7409bdb5652c5b05145626506651010f58a854c47712065334c61ff39c +DIST winnow-0.6.13.crate 162649 BLAKE2B f088396ccdc6e96e56b822c20ea483eaead57794e101bff3df6ea35fe039fa2dcf2eac98dabebc3decb4129c200490633f05ba5dd4325cec29d28c78887c3de1 SHA512 a8a94c26afc4cc4db6ec2e65e7bff325fbe6816d4a80fb97e2014e202af0f549a77518f0435157985822aa9fd8642b95258b6cf87a9e695f4b9a11b5fe514d86 +DIST winnow-0.6.2.crate 157140 BLAKE2B 2cb9e63875403fe525739e2e20d4351f51b6f52dc03928af6de4531f388ec5cd0af7e21ef2f621330f7c91b01eb644fafd0618a246ce3c3dfe61d801e8f8e0e3 SHA512 dd54d69f7ce91f7ac2503ec79bf5bc3e45d2e8b0a3fc593487af33396f819c9df145eacd5ab43ecedca592a89ef259351314335de3fe740a05af5889f24fa8a5 +DIST winsafe-0.0.19.crate 492820 BLAKE2B 4eba26861f85f668e134b08c60e9522b698aed61eaa5e6d4e89ef31c1b97953fa08a5157add52d9a306075df4ad97e9aaf1767eea4208b72401ec0bc1c3eb0e9 SHA512 0555ec74c5acbb69ab08e54d920094e806258079bffaff3f90297bb94a000c7da36d6eba0eae445d425c781465235dd70a198437cf83a1f113438bfd9baf4c21 +DIST xattr-1.3.1.crate 12580 BLAKE2B 25c414d761a7fcd23bbe057add62c6da971cf33149066aa024320ab80e0ec8e8e8d5d3d0506e8de954b8f8c178d34c52a00a5fa9aa109510678098a3e3564b7f SHA512 4047abda42b949cf58f820e15ee99850de483857bbaaef737eeee48e1a2132972470f15bb2ddda56438f6a934918be96607a8de518a5a3dcec7c8ee6c00ad280 +DIST xwin-0.5.0.crate 65006 BLAKE2B 8b4f979120ecfe1e1b38830b2230b1e195a88a91cb1b56c43da211dfa9f7b41ca48aa3dda12b65ba1b3b7e3bfec989433f7b743875c780dfee49c1d2cf38cea9 SHA512 1268bb25e7ae98f97a608acb23997799fbd84a097be35f403b4f2c5a55058960852c8d3e96a509f0022ee7ff79f8671c563a93e8f0fa699d461c5faf41c17730 +DIST xwin-0.5.1.crate 65009 BLAKE2B 91403c2d890b2ab48a94356eab78f3bae08d18d98746824be64c9be6f6af5e1856ab7c7ba1faaf3ef4a2e92e4767cb45ed69c3d24bf668082db22ca988adb805 SHA512 2bbd5336155f7a4dca1671f5018965f875c26eb71b34806664d9a2051d875886eaaaa9b9a989fbca6d22b4a29bf8acaa453b006724102717d2c57c1636ab972e +DIST yansi-0.5.1.crate 16525 BLAKE2B 3b5a93b98293daae72f53bf3f13bfc05feba8d5b27921f79595f7448fbcb9a0dfa6cd70f467c5735b914c46b7d3592e6cce080c540a458a904308525eb3aa839 SHA512 7b33005a066cc612408a65df6533e8718d1de43efc0fd57416a19dc2b811497570e6e18f100fb26073565e395e711518c27de7d644ae64777713f1a102eb16d2 +DIST yansi-1.0.1.crate 75497 BLAKE2B c0d396c93a733ed6ec12aca3385d816f39b1f1fbed75da460f491f0cbfc30ba462842ebd1627fa8e5d2b7c0f37913a23747e5f5e23df1cb7c85d965e6c37159b SHA512 182c8c6c60a30a727d8f8b90bbf0527d91fa8ae9d8eb20e5414614b43ee6dc532f4b19241adbfb9299cb0004b39fe627036269b60b0c3860d9e1ea4413aca541 +DIST zerocopy-0.7.32.crate 151096 BLAKE2B 12c7c329ec0e0865467af08306ff4b55ce1e39fd77b094ee48ed9c6e266dfa807bda9ea72a3f7ea989916327f4d9e803d8868995728bfe2fb1c2dc1e5ecff78e SHA512 6729b05eb88029555b88c75feff4f8bc28ad9675edb02b07486381f775c8650c95e2e59612906bd9c34c5e390fd339857ca91573ee9f9ca7948572cff4171c82 +DIST zerocopy-0.7.34.crate 151177 BLAKE2B 30b65131370dfa4f41d3c2705d3b75da9b76f2a4ed723dec66345939de8bafe2c181ab6c98036c25a30739cae1720d927e27e5fa5587442d5cfb7f39a7018c8f SHA512 4d27b1230ebcea4e9d4c15f38a979aa3fe8b23833e95df781a0a67054e920637642b89345596fe331907edc27abab83c766967f2a04399a6fe0a4e89fa0dd148 +DIST zerocopy-derive-0.7.32.crate 37623 BLAKE2B 8b583d39d7bf9c3dbbba578120751c664f87363c5ba3fc45f6506a4059b9e599c43d9fc7bd498a257ff7c9d872af77d39bebdb0e65fb8009eaa2ae9903dece46 SHA512 3ce8528871fd18d6abe92b98503927451d25791c9c4af0ba39a3b6ba2006030bdc137084d080e9b1ac8b5ddf5f2121e0a3ef34bb2033a040f2c72c8149a9fc0d +DIST zerocopy-derive-0.7.34.crate 37907 BLAKE2B 23a698c3c892187307007cbc76c9338dbe163e4f14d4ea73969ba834f5c6732d16f5bc26e2e85c5e3df2100b28e6e72ae6473b2159f5160ee19befdef3615f98 SHA512 1bd93062b0d2c699066f8a991326b4470426aae0517d33748a8f0e52b009fc46e6b0b238abe97462a2e13c870fa3d0d070615870e6dbbf8b6991c0e3fb5c3e63 +DIST zeroize-1.7.0.crate 19039 BLAKE2B 2f94a5025f409bd2b96a456d2f78a34c6b05b5554abe7ef3fad2a55a8fcff8a6a1b971be660aa4c2954ab7d6e89bebc431036e349edef74711292f9f64b1dbae SHA512 9d31e3e76e8c861309a3579c21f6da5fd6b056c7d7a350427445a1a832e8827204804783f7f9b808acaa2148efef883d9078bf84943b1db55526bba5bf5a2756 +DIST zeroize-1.8.1.crate 20029 BLAKE2B 092eba034cd35ec47290020e0c2b213177ff5dbe14ab9e7f0b4ef3cb1ecbc42fbec2b951414e26ab00bc65aaddc2c93eddd5a1963b27c6cd613ac71c65d5cc24 SHA512 dd40ebe98b98fd742608d4066b5ab66caba94b2e679428fcaff9fe547d8cd6ff2360dc85d671ee9183e32fb79cb554d00d6aef9eb8f3d8ad0ec92d0435aa4ebe +DIST zip-0.6.6.crate 65789 BLAKE2B acefc076297468d72cb20d8c6234fe5406875056fbf78fc0eac3ac430af78f320ed839f8683bd96fa1a03c457d6ac568d42bd703a902bc37bd126791d8b4c709 SHA512 affd46c17ceaa0545a155250dfd16756f8706dda43bae8a322ec0481dbfb41e4cf3166bf9662fc139ef9d0ab3b0f9f158535b21d2a61b21d38b8b2407813eeef +DIST zip-1.1.4.crate 77910 BLAKE2B 1c6a0e14becbb43faa9510d303ab254486e97730bc741c1fa3c7a88327da0b1e8815026e319abdbeb9e6c9e0ec713d83dbb3a0ae83a32ed2d197923afa803866 SHA512 18c8e7c9246049c7be4ade2bee501da2ff7cfe45aaab88e20650246833ae3f7b492644c0f4a43aa93a7ef7bf95413c9b27d0f5f8d099f19131a682b92a6d3fc4 diff --git a/sdk_container/src/third_party/portage-stable/dev-util/maturin/maturin-1.6.0.ebuild b/sdk_container/src/third_party/portage-stable/dev-util/maturin/maturin-1.6.0.ebuild new file mode 100644 index 00000000000..74050422364 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-util/maturin/maturin-1.6.0.ebuild @@ -0,0 +1,576 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +CRATES=" + adler@1.0.2 + ahash@0.8.7 + aho-corasick@1.1.2 + allocator-api2@0.2.16 + anstream@0.6.11 + anstyle-parse@0.2.3 + anstyle-query@1.0.2 + anstyle-wincon@3.0.2 + anstyle@1.0.4 + anyhow@1.0.80 + autocfg@1.1.0 + base64@0.13.1 + base64@0.21.7 + bitflags@1.3.2 + bitflags@2.4.2 + block-buffer@0.10.4 + bstr@1.9.0 + byteorder@1.5.0 + bytesize@1.3.0 + bytes@1.5.0 + bzip2-sys@0.1.11+1.0.8 + bzip2@0.4.4 + cab@0.4.1 + camino@1.1.6 + cargo-config2@0.1.24 + cargo-options@0.7.4 + cargo-platform@0.1.6 + cargo-xwin@0.16.4 + cargo-zigbuild@0.18.4 + cargo_metadata@0.18.1 + cbindgen@0.26.0 + cc@1.0.88 + cfb@0.9.0 + cfg-if@1.0.0 + charset@0.1.3 + chumsky@0.9.3 + clap@4.4.18 + clap_builder@4.4.18 + clap_complete@4.4.9 + clap_complete_command@0.5.1 + clap_complete_nushell@0.1.11 + clap_derive@4.4.7 + clap_lex@0.6.0 + cli-table@0.4.7 + colorchoice@1.0.0 + configparser@3.0.4 + console@0.15.8 + content_inspector@0.2.4 + core-foundation-sys@0.8.6 + core-foundation@0.9.4 + cpufeatures@0.2.12 + crc32fast@1.3.2 + crossbeam-channel@0.5.11 + crossbeam-deque@0.8.5 + crossbeam-epoch@0.9.18 + crossbeam-utils@0.8.19 + crypto-common@0.1.6 + data-encoding@2.5.0 + deranged@0.3.11 + derivative@2.2.0 + dialoguer@0.11.0 + diff@0.1.13 + digest@0.10.7 + dirs-sys@0.4.1 + dirs@5.0.1 + dissimilar@1.0.7 + dunce@1.0.4 + dyn-clone@1.0.17 + either@1.9.0 + encode_unicode@0.3.6 + encoding_rs@0.8.33 + equivalent@1.0.1 + errno@0.3.8 + expect-test@1.4.1 + fastrand@2.0.1 + fat-macho@0.4.8 + filetime@0.2.23 + flate2@1.0.28 + fnv@1.0.7 + foreign-types-shared@0.1.1 + foreign-types@0.3.2 + form_urlencoded@1.2.1 + fs-err@2.11.0 + futures-channel@0.3.30 + futures-core@0.3.30 + futures-executor@0.3.30 + futures-io@0.3.30 + futures-macro@0.3.30 + futures-sink@0.3.30 + futures-task@0.3.30 + futures-timer@3.0.3 + futures-util@0.3.30 + futures@0.3.30 + generic-array@0.14.7 + getrandom@0.2.12 + globset@0.4.14 + glob@0.3.1 + goblin@0.8.0 + hashbrown@0.12.3 + hashbrown@0.14.3 + heck@0.4.1 + home@0.5.9 + humantime-serde@1.1.1 + humantime@2.1.0 + idna@0.5.0 + ignore@0.4.22 + indexmap@1.9.3 + indexmap@2.2.3 + indicatif@0.17.7 + indoc@2.0.4 + instant@0.1.12 + itertools@0.11.0 + itertools@0.12.1 + itoa@1.0.10 + keyring@2.3.2 + lazy_static@1.4.0 + lddtree@0.3.4 + libc@0.2.153 + libredox@0.0.1 + linux-keyutils@0.2.4 + linux-raw-sys@0.4.13 + lock_api@0.4.11 + log@0.4.20 + lzxd@0.1.4 + mailparse@0.14.1 + matchers@0.1.0 + memchr@2.7.1 + mime@0.3.17 + mime_guess@2.0.4 + minijinja@1.0.12 + minimal-lexical@0.2.1 + miniz_oxide@0.7.1 + msi@0.7.0 + multipart@0.18.0 + native-tls@0.2.11 + nom@7.1.3 + normalize-line-endings@0.3.0 + normpath@1.1.1 + number_prefix@0.4.0 + num-conv@0.1.0 + nu-ansi-term@0.46.0 + once_cell@1.19.0 + openssl-macros@0.1.1 + openssl-probe@0.1.5 + openssl-sys@0.9.99 + openssl@0.10.63 + option-ext@0.2.0 + os_pipe@1.1.5 + overload@0.1.1 + parking_lot@0.12.1 + parking_lot_core@0.9.9 + paste@1.0.14 + path-slash@0.2.1 + pep440_rs@0.5.0 + pep508_rs@0.4.2 + percent-encoding@2.3.1 + pin-project-lite@0.2.13 + pin-utils@0.1.0 + pkg-config@0.3.29 + plain@0.2.3 + platform-info@2.0.2 + portable-atomic@1.6.0 + powerfmt@0.2.0 + ppv-lite86@0.2.17 + pretty_assertions@1.4.0 + proc-macro2@1.0.78 + psm@0.1.21 + pyproject-toml@0.10.0 + python-pkginfo@0.6.0 + quoted_printable@0.4.8 + quoted_printable@0.5.0 + quote@1.0.35 + rand@0.8.5 + rand_chacha@0.3.1 + rand_core@0.6.4 + rayon-core@1.12.1 + rayon@1.8.1 + redox_syscall@0.4.1 + redox_users@0.4.4 + regex-automata@0.1.10 + regex-automata@0.4.5 + regex-syntax@0.6.29 + regex-syntax@0.8.2 + regex@1.10.3 + relative-path@1.9.2 + rfc2047-decoder@0.2.2 + ring@0.17.7 + rstest@0.18.2 + rstest_macros@0.18.2 + rustc_version@0.4.0 + rustix@0.38.32 + rustls-pemfile@2.1.0 + rustls-pki-types@1.3.1 + rustls-webpki@0.102.1 + rustls@0.22.4 + rustversion@1.0.14 + ryu@1.0.16 + same-file@1.0.6 + schannel@0.1.23 + schemars@0.8.16 + schemars_derive@0.8.16 + scopeguard@1.2.0 + scroll@0.12.0 + scroll_derive@0.12.0 + security-framework-sys@2.9.1 + security-framework@2.9.2 + semver@1.0.22 + serde@1.0.197 + serde_derive@1.0.197 + serde_derive_internals@0.26.0 + serde_json@1.0.114 + serde_spanned@0.6.5 + sha2@0.10.8 + sharded-slab@0.1.7 + shell-words@1.1.0 + shlex@1.3.0 + similar@2.4.0 + slab@0.4.9 + smallvec@1.13.1 + smawk@0.3.2 + snapbox-macros@0.3.8 + snapbox@0.5.7 + socks@0.3.4 + spin@0.9.8 + stacker@0.1.15 + static_assertions@1.1.0 + strsim@0.10.0 + subtle@2.5.0 + syn@1.0.109 + syn@2.0.48 + target-lexicon@0.12.14 + tar@0.4.40 + tempfile@3.9.0 + termcolor@1.4.1 + terminal_size@0.3.0 + textwrap@0.16.1 + thiserror-impl@1.0.57 + thiserror@1.0.57 + thread_local@1.1.7 + time-core@0.1.2 + time-macros@0.2.17 + time@0.3.34 + tinyvec@1.6.0 + tinyvec_macros@0.1.1 + toml@0.5.11 + toml@0.8.10 + toml_datetime@0.6.5 + toml_edit@0.22.6 + tracing-attributes@0.1.27 + tracing-core@0.1.32 + tracing-log@0.2.0 + tracing-serde@0.1.3 + tracing-subscriber@0.3.18 + tracing@0.1.40 + trycmd@0.15.0 + twox-hash@1.6.3 + typenum@1.17.0 + unicase@2.7.0 + unicode-bidi@0.3.15 + unicode-ident@1.0.12 + unicode-linebreak@0.1.5 + unicode-normalization@0.1.22 + unicode-width@0.1.11 + unicode-xid@0.2.4 + unscanny@0.1.0 + untrusted@0.9.0 + ureq@2.9.6 + urlencoding@2.1.3 + url@2.5.0 + utf8parse@0.2.1 + uuid@1.7.0 + valuable@0.1.0 + vcpkg@0.2.15 + versions@5.0.1 + version_check@0.9.4 + wait-timeout@0.2.0 + walkdir@2.4.0 + wasi@0.11.0+wasi-snapshot-preview1 + webpki-roots@0.26.0 + which@5.0.0 + which@6.0.0 + wild@2.2.1 + winapi-i686-pc-windows-gnu@0.4.0 + winapi-util@0.1.6 + winapi-x86_64-pc-windows-gnu@0.4.0 + winapi@0.3.9 + windows-sys@0.48.0 + windows-sys@0.52.0 + windows-targets@0.48.5 + windows-targets@0.52.0 + windows_aarch64_gnullvm@0.48.5 + windows_aarch64_gnullvm@0.52.0 + windows_aarch64_msvc@0.48.5 + windows_aarch64_msvc@0.52.0 + windows_i686_gnu@0.48.5 + windows_i686_gnu@0.52.0 + windows_i686_msvc@0.48.5 + windows_i686_msvc@0.52.0 + windows_x86_64_gnullvm@0.48.5 + windows_x86_64_gnullvm@0.52.0 + windows_x86_64_gnu@0.48.5 + windows_x86_64_gnu@0.52.0 + windows_x86_64_msvc@0.48.5 + windows_x86_64_msvc@0.52.0 + winnow@0.6.2 + xattr@1.3.1 + xwin@0.5.0 + yansi@0.5.1 + zerocopy-derive@0.7.32 + zerocopy@0.7.32 + zeroize@1.7.0 + zip@0.6.6 +" +# additional crates used by test-crates/* test packages, +# `grep test-crates tests/run.rs` to see which are needed +CRATES_TEST=" + anstream@0.3.2 + anstyle-parse@0.2.1 + anstyle-query@1.0.0 + anstyle-wincon@1.0.2 + anstyle@1.0.1 + anyhow@1.0.72 + askama@0.12.0 + askama_derive@0.12.1 + askama_escape@0.10.3 + basic-toml@0.1.4 + bincode@1.3.3 + bitflags@2.4.0 + bytes@1.4.0 + cargo-platform@0.1.3 + cargo_metadata@0.15.4 + cc@1.0.73 + cc@1.0.81 + cc@1.0.82 + cc@1.0.83 + clap@4.3.21 + clap_builder@4.3.21 + clap_derive@4.3.12 + clap_lex@0.5.0 + errno-dragonfly@0.1.2 + errno@0.3.2 + fs-err@2.9.0 + getrandom@0.2.10 + hermit-abi@0.3.2 + is-terminal@0.4.9 + itoa@1.0.9 + libc@0.2.134 + libc@0.2.147 + libc@0.2.149 + linux-raw-sys@0.4.10 + lock_api@0.4.9 + lock_api@0.4.10 + log@0.4.19 + memchr@2.5.0 + memoffset@0.9.0 + once_cell@1.15.0 + once_cell@1.18.0 + oneshot-uniffi@0.1.6 + parking_lot_core@0.9.3 + parking_lot_core@0.9.8 + proc-macro2@1.0.66 + proc-macro2@1.0.69 + proc-macro2@1.0.70 + pyo3-build-config@0.18.3 + pyo3-build-config@0.21.0 + pyo3-ffi@0.18.3 + pyo3-ffi@0.21.0 + pyo3-macros-backend@0.21.0 + pyo3-macros@0.21.0 + pyo3@0.21.0 + python3-dll-a@0.2.6 + python3-dll-a@0.2.9 + quote@1.0.32 + quote@1.0.33 + redox_syscall@0.2.16 + redox_syscall@0.3.5 + rustix@0.38.21 + ryu@1.0.15 + scopeguard@1.1.0 + semver@1.0.18 + serde@1.0.182 + serde@1.0.183 + serde_derive@1.0.182 + serde_derive@1.0.183 + serde_json@1.0.104 + siphasher@0.3.10 + smallvec@1.10.0 + smallvec@1.11.0 + smallvec@1.11.1 + syn@2.0.28 + syn@2.0.32 + syn@2.0.40 + target-lexicon@0.12.7 + target-lexicon@0.12.11 + target-lexicon@0.12.12 + textwrap@0.16.0 + thiserror-impl@1.0.44 + thiserror@1.0.44 + unicase@2.6.0 + unicode-ident@1.0.5 + unicode-ident@1.0.11 + uniffi@0.27.0 + uniffi_bindgen@0.27.0 + uniffi_build@0.27.0 + uniffi_checksum_derive@0.27.0 + uniffi_core@0.27.0 + uniffi_macros@0.27.0 + uniffi_meta@0.27.0 + uniffi_testing@0.27.0 + uniffi_udl@0.27.0 + unindent@0.2.3 + weedle2@5.0.0 + windows-sys@0.36.1 + windows-targets@0.48.1 + windows_aarch64_gnullvm@0.48.0 + windows_aarch64_msvc@0.36.1 + windows_aarch64_msvc@0.48.0 + windows_i686_gnu@0.36.1 + windows_i686_gnu@0.48.0 + windows_i686_msvc@0.36.1 + windows_i686_msvc@0.48.0 + windows_x86_64_gnullvm@0.48.0 + windows_x86_64_gnu@0.36.1 + windows_x86_64_gnu@0.48.0 + windows_x86_64_msvc@0.36.1 + windows_x86_64_msvc@0.48.0 +" +DISTUTILS_USE_PEP517=setuptools +PYTHON_COMPAT=( pypy3 python3_{10..13} ) +inherit cargo distutils-r1 flag-o-matic shell-completion toolchain-funcs + +DESCRIPTION="Build and publish crates with pyo3, rust-cpython and cffi bindings" +HOMEPAGE="https://www.maturin.rs/" +SRC_URI=" + https://github.com/PyO3/maturin/archive/refs/tags/v${PV}.tar.gz + -> ${P}.gh.tar.gz + ${CARGO_CRATE_URIS} + test? ( $(cargo_crate_uris ${CRATES_TEST}) ) +" + +# note: ring is unused, so openssl license can be skipped +LICENSE="|| ( Apache-2.0 MIT ) doc? ( CC-BY-4.0 OFL-1.1 )" +LICENSE+=" + 0BSD Apache-2.0 Apache-2.0-with-LLVM-exceptions BSD ISC MIT MPL-2.0 + Unicode-DFS-2016 +" # crates +SLOT="0" +KEYWORDS="amd64 arm arm64 ~loong ppc ppc64 ~riscv ~s390 sparc x86" +IUSE="doc +ssl test" +RESTRICT="!test? ( test )" + +RDEPEND="$(python_gen_cond_dep 'dev-python/tomli[${PYTHON_USEDEP}]' 3.10)" +DEPEND="ssl? ( dev-libs/openssl:= )" +BDEPEND=" + virtual/pkgconfig + doc? ( app-text/mdbook ) + test? ( + ${RDEPEND} + $(python_gen_cond_dep 'dev-python/cffi[${PYTHON_USEDEP}]' 'python*') + dev-python/boltons[${PYTHON_USEDEP}] + dev-python/virtualenv[${PYTHON_USEDEP}] + dev-vcs/git + elibc_musl? ( dev-util/patchelf ) + ) +" +RDEPEND+=" ${DEPEND}" + +QA_FLAGS_IGNORED="usr/bin/${PN}" + +src_prepare() { + distutils-r1_src_prepare + + # we build the Rust executable (just once) via cargo_src_compile + sed -i -e '/setuptools_rust/d' -e '/rust_extensions/d' setup.py || die + + if use test; then + # used to prevent use of network during tests, and silence pip + # if it finds unrelated issues with system packages (bug #913613) + cat > "${T}"/pip.conf <<-EOF || die + [global] + quiet = 2 + + [install] + no-index = yes + no-dependencies = yes + EOF + + # used by *git_sdist_generator tests + git init -q || die + git config --global user.email "larry@gentoo.org" || die + git config --global user.name "Larry the Cow" || die + git add . || die + git commit -qm init || die + fi +} + +src_configure() { + export OPENSSL_NO_VENDOR=1 + + # bug #938847 (TODO?: should probably be an eclass default for musl) + use elibc_musl && RUSTFLAGS+=" -C target-feature=-crt-static" + + # https://github.com/rust-lang/stacker/issues/79 + use s390 && ! is-flagq '-march=*' && + append-cflags $(test-flags-CC -march=z10) + + local myfeatures=( + # like release.yml + native-tls for better platform support than rustls + full + password-storage + $(usev ssl native-tls) + ) + + cargo_src_configure --no-default-features +} + +python_compile_all() { + cargo_src_compile + + use !doc || mdbook build -d html guide || die + + if ! tc-is-cross-compiler; then + local maturin=$(cargo_target_dir)/maturin + ${maturin} completions bash > "${T}"/${PN} || die + ${maturin} completions fish > "${T}"/${PN}.fish || die + ${maturin} completions zsh > "${T}"/_${PN} || die + else + ewarn "shell completion files were skipped due to cross-compilation" + fi +} + +python_test() { + local -x MATURIN_TEST_PYTHON=${EPYTHON} + local -x PIP_CONFIG_FILE=${T}/pip.conf + local -x VIRTUALENV_SYSTEM_SITE_PACKAGES=1 + + # need this for (new) python versions not yet recognized by pyo3 + local -x PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 + + local skip=( + # picky cli output test that easily benignly fail (bug #937992) + --skip cli_tests + # avoid need for wasm over a single hello world test + --skip integration_wasm_hello_world + # fragile depending on rust version, also wants libpypy*-c.so for pypy + --skip pyo3_no_extension_module + # unimportant tests that use uv, and it does not seem to be able + # to find the system's dev-python/uv (not worth the trouble) + --skip develop_hello_world::case_2 + --skip develop_pyo3_ffi_pure::case_2 + # fails on sparc since rust-1.74 (bug #934573), skip for now given + # should not affect the pep517 backend which is all we need on sparc + $(usev sparc '--skip build_context::test::test_macosx_deployment_target') + ) + + cargo_src_test -- "${skip[@]}" +} + +python_install_all() { + cargo_src_install + + dodoc Changelog.md README.md + use doc && dodoc -r guide/html + + if ! tc-is-cross-compiler; then + dobashcomp "${T}"/${PN} + dofishcomp "${T}"/${PN}.fish + dozshcomp "${T}"/_${PN} + fi +} diff --git a/sdk_container/src/third_party/portage-stable/dev-util/maturin/maturin-1.7.1.ebuild b/sdk_container/src/third_party/portage-stable/dev-util/maturin/maturin-1.7.1.ebuild new file mode 100644 index 00000000000..43313529f45 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-util/maturin/maturin-1.7.1.ebuild @@ -0,0 +1,541 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +CRATES=" + adler@1.0.2 + ahash@0.8.11 + aho-corasick@1.1.3 + allocator-api2@0.2.18 + anstream@0.6.14 + anstyle-parse@0.2.4 + anstyle-query@1.1.0 + anstyle-wincon@3.0.3 + anstyle@1.0.7 + anyhow@1.0.86 + arbitrary@1.3.2 + autocfg@1.3.0 + automod@1.0.14 + base64@0.13.1 + base64@0.21.7 + base64@0.22.1 + bitflags@1.3.2 + bitflags@2.5.0 + block-buffer@0.10.4 + bstr@1.9.1 + byteorder@1.5.0 + bytesize@1.3.0 + bytes@1.6.0 + bzip2-sys@0.1.11+1.0.8 + bzip2@0.4.4 + cab@0.5.0 + camino@1.1.7 + cargo-config2@0.1.26 + cargo-options@0.7.4 + cargo-platform@0.1.8 + cargo-xwin@0.16.5 + cargo-zigbuild@0.18.4 + cargo_metadata@0.18.1 + cbindgen@0.26.0 + cc@1.1.6 + cfb@0.9.0 + cfg-if@1.0.0 + charset@0.1.3 + chumsky@0.9.3 + clap@4.5.7 + clap_builder@4.5.7 + clap_complete@4.5.5 + clap_complete_command@0.6.1 + clap_complete_nushell@4.5.2 + clap_derive@4.5.5 + clap_lex@0.7.1 + cli-table@0.4.7 + colorchoice@1.0.1 + configparser@3.1.0 + console@0.15.8 + content_inspector@0.2.4 + core-foundation-sys@0.8.6 + core-foundation@0.9.4 + cpufeatures@0.2.12 + crc32fast@1.4.2 + crossbeam-channel@0.5.13 + crossbeam-deque@0.8.5 + crossbeam-epoch@0.9.18 + crossbeam-utils@0.8.20 + crypto-common@0.1.6 + data-encoding@2.6.0 + deranged@0.3.11 + derivative@2.2.0 + derive_arbitrary@1.3.2 + dialoguer@0.11.0 + diff@0.1.13 + digest@0.10.7 + dirs-sys@0.4.1 + dirs@5.0.1 + displaydoc@0.2.4 + dissimilar@1.0.9 + dunce@1.0.4 + dyn-clone@1.0.17 + either@1.12.0 + encode_unicode@0.3.6 + encoding_rs@0.8.34 + equivalent@1.0.1 + errno@0.3.9 + expect-test@1.5.0 + fastrand@2.1.0 + fat-macho@0.4.8 + filetime@0.2.23 + flate2@1.0.30 + fnv@1.0.7 + foreign-types-shared@0.1.1 + foreign-types@0.3.2 + form_urlencoded@1.2.1 + fs-err@2.11.0 + futures-channel@0.3.30 + futures-core@0.3.30 + futures-executor@0.3.30 + futures-io@0.3.30 + futures-macro@0.3.30 + futures-sink@0.3.30 + futures-task@0.3.30 + futures-timer@3.0.3 + futures-util@0.3.30 + futures@0.3.30 + generic-array@0.14.7 + getrandom@0.2.15 + globset@0.4.14 + glob@0.3.1 + goblin@0.8.2 + hashbrown@0.12.3 + hashbrown@0.14.5 + heck@0.4.1 + heck@0.5.0 + home@0.5.9 + humantime-serde@1.1.1 + humantime@2.1.0 + idna@0.5.0 + ignore@0.4.22 + indexmap@1.9.3 + indexmap@2.2.6 + indicatif@0.17.8 + indoc@2.0.5 + instant@0.1.13 + is_terminal_polyfill@1.70.0 + itertools@0.12.1 + itoa@1.0.11 + keyring@2.3.3 + lazy_static@1.4.0 + lddtree@0.3.5 + libc@0.2.155 + libmimalloc-sys@0.1.38 + libredox@0.1.3 + linux-keyutils@0.2.4 + linux-raw-sys@0.4.14 + lock_api@0.4.12 + log@0.4.21 + lzxd@0.2.5 + mailparse@0.15.0 + matchers@0.1.0 + memchr@2.7.2 + mimalloc@0.1.42 + mime@0.3.17 + mime_guess@2.0.4 + minijinja@1.0.21 + minimal-lexical@0.2.1 + miniz_oxide@0.7.3 + msi@0.7.0 + multipart@0.18.0 + native-tls@0.2.12 + nom@7.1.3 + normalize-line-endings@0.3.0 + normpath@1.2.0 + number_prefix@0.4.0 + num-conv@0.1.0 + num_enum@0.7.2 + num_enum_derive@0.7.2 + nu-ansi-term@0.46.0 + once_cell@1.19.0 + openssl-macros@0.1.1 + openssl-probe@0.1.5 + openssl-sys@0.9.103 + openssl@0.10.66 + option-ext@0.2.0 + os_pipe@1.2.0 + overload@0.1.1 + parking_lot@0.12.3 + parking_lot_core@0.9.10 + paste@1.0.15 + path-slash@0.2.1 + pep440_rs@0.6.0 + pep508_rs@0.6.0 + percent-encoding@2.3.1 + pin-project-lite@0.2.14 + pin-utils@0.1.0 + pkg-config@0.3.30 + plain@0.2.3 + platform-info@2.0.3 + portable-atomic@1.6.0 + powerfmt@0.2.0 + ppv-lite86@0.2.17 + pretty_assertions@1.4.0 + proc-macro2@1.0.85 + proc-macro-crate@3.1.0 + psm@0.1.21 + pyproject-toml@0.11.0 + python-pkginfo@0.6.2 + quoted_printable@0.5.0 + quote@1.0.36 + rand@0.8.5 + rand_chacha@0.3.1 + rand_core@0.6.4 + rayon-core@1.12.1 + rayon@1.10.0 + redox_syscall@0.4.1 + redox_syscall@0.5.1 + redox_users@0.4.5 + regex-automata@0.1.10 + regex-automata@0.4.7 + regex-syntax@0.6.29 + regex-syntax@0.8.4 + regex@1.10.5 + relative-path@1.9.3 + rfc2047-decoder@1.0.5 + ring@0.17.8 + rstest@0.21.0 + rstest_macros@0.21.0 + rustc_version@0.4.0 + rustix@0.38.34 + rustls-pemfile@2.1.2 + rustls-pki-types@1.7.0 + rustls-webpki@0.102.4 + rustls@0.22.4 + rustversion@1.0.17 + ryu@1.0.18 + same-file@1.0.6 + schannel@0.1.23 + schemars@0.8.21 + schemars_derive@0.8.21 + scopeguard@1.2.0 + scroll@0.12.0 + scroll_derive@0.12.0 + security-framework-sys@2.11.0 + security-framework@2.11.0 + semver@1.0.23 + serde@1.0.204 + serde_derive@1.0.204 + serde_derive_internals@0.29.1 + serde_json@1.0.120 + serde_spanned@0.6.6 + sha2@0.10.8 + sharded-slab@0.1.7 + shell-words@1.1.0 + shlex@1.3.0 + similar@2.5.0 + slab@0.4.9 + smallvec@1.13.2 + smawk@0.3.2 + snapbox-macros@0.3.9 + snapbox@0.6.10 + socks@0.3.4 + spin@0.9.8 + stacker@0.1.15 + static_assertions@1.1.0 + strsim@0.11.1 + subtle@2.5.0 + syn@1.0.109 + syn@2.0.66 + target-lexicon@0.12.15 + tar@0.4.41 + tempfile@3.10.1 + termcolor@1.4.1 + terminal_size@0.3.0 + textwrap@0.16.1 + thiserror-impl@1.0.61 + thiserror@1.0.61 + thread_local@1.1.8 + time-core@0.1.2 + time-macros@0.2.18 + time@0.3.36 + tinyvec@1.7.0 + tinyvec_macros@0.1.1 + toml@0.5.11 + toml@0.8.14 + toml_datetime@0.6.6 + toml_edit@0.21.1 + toml_edit@0.22.14 + tracing-attributes@0.1.27 + tracing-core@0.1.32 + tracing-log@0.2.0 + tracing-serde@0.1.3 + tracing-subscriber@0.3.18 + tracing@0.1.40 + trycmd@0.15.4 + twox-hash@1.6.3 + typenum@1.17.0 + unicase@2.7.0 + unicode-bidi@0.3.15 + unicode-ident@1.0.12 + unicode-linebreak@0.1.5 + unicode-normalization@0.1.23 + unicode-width@0.1.13 + unicode-xid@0.2.4 + unscanny@0.1.0 + untrusted@0.9.0 + ureq@2.9.7 + urlencoding@2.1.3 + url@2.5.2 + utf8parse@0.2.2 + uuid@1.8.0 + valuable@0.1.0 + vcpkg@0.2.15 + versions@6.2.0 + version_check@0.9.4 + wait-timeout@0.2.0 + walkdir@2.5.0 + wasi@0.11.0+wasi-snapshot-preview1 + webpki-roots@0.26.2 + which@5.0.0 + which@6.0.1 + wild@2.2.1 + winapi-i686-pc-windows-gnu@0.4.0 + winapi-util@0.1.8 + winapi-x86_64-pc-windows-gnu@0.4.0 + winapi@0.3.9 + windows-sys@0.48.0 + windows-sys@0.52.0 + windows-targets@0.48.5 + windows-targets@0.52.5 + windows_aarch64_gnullvm@0.48.5 + windows_aarch64_gnullvm@0.52.5 + windows_aarch64_msvc@0.48.5 + windows_aarch64_msvc@0.52.5 + windows_i686_gnullvm@0.52.5 + windows_i686_gnu@0.48.5 + windows_i686_gnu@0.52.5 + windows_i686_msvc@0.48.5 + windows_i686_msvc@0.52.5 + windows_x86_64_gnullvm@0.48.5 + windows_x86_64_gnullvm@0.52.5 + windows_x86_64_gnu@0.48.5 + windows_x86_64_gnu@0.52.5 + windows_x86_64_msvc@0.48.5 + windows_x86_64_msvc@0.52.5 + winnow@0.5.40 + winnow@0.6.13 + winsafe@0.0.19 + xattr@1.3.1 + xwin@0.5.1 + yansi@0.5.1 + zerocopy-derive@0.7.34 + zerocopy@0.7.34 + zeroize@1.8.1 + zip@0.6.6 + zip@1.1.4 +" +# additional crates used by test-crates/* test packages, +# `grep test-crates tests/run.rs` to see which are needed +CRATES_TEST=" + askama@0.12.1 + askama_derive@0.12.5 + askama_escape@0.10.3 + askama_parser@0.2.1 + autocfg@1.1.0 + basic-toml@0.1.9 + bincode@1.3.3 + cargo_metadata@0.15.4 + cc@1.0.73 + cc@1.0.81 + cc@1.0.83 + getrandom@0.2.10 + indoc@2.0.4 + libc@0.2.134 + libc@0.2.147 + libc@0.2.149 + memchr@2.7.4 + memoffset@0.9.0 + memoffset@0.9.1 + once_cell@1.15.0 + once_cell@1.18.0 + portable-atomic@1.7.0 + proc-macro2@1.0.86 + pyo3-build-config@0.18.3 + pyo3-build-config@0.22.0 + pyo3-build-config@0.22.2 + pyo3-ffi@0.18.3 + pyo3-ffi@0.22.0 + pyo3-ffi@0.22.2 + pyo3-macros-backend@0.22.0 + pyo3-macros-backend@0.22.2 + pyo3-macros@0.22.0 + pyo3-macros@0.22.2 + pyo3@0.22.0 + pyo3@0.22.2 + python3-dll-a@0.2.6 + python3-dll-a@0.2.9 + serde@1.0.203 + serde_derive@1.0.203 + serde_json@1.0.118 + siphasher@0.3.11 + syn@2.0.68 + syn@2.0.72 + target-lexicon@0.12.11 + target-lexicon@0.12.14 + target-lexicon@0.12.16 + unicode-ident@1.0.5 + unicode-ident@1.0.11 + uniffi@0.28.0 + uniffi_bindgen@0.28.0 + uniffi_build@0.28.0 + uniffi_checksum_derive@0.28.0 + uniffi_core@0.28.0 + uniffi_macros@0.28.0 + uniffi_meta@0.28.0 + uniffi_testing@0.28.0 + uniffi_udl@0.28.0 + unindent@0.2.3 + weedle2@5.0.0 +" +DISTUTILS_USE_PEP517=setuptools +PYTHON_COMPAT=( pypy3 python3_{10..13} ) +inherit cargo distutils-r1 flag-o-matic shell-completion toolchain-funcs + +DESCRIPTION="Build and publish crates with pyo3, rust-cpython and cffi bindings" +HOMEPAGE="https://www.maturin.rs/" +SRC_URI=" + https://github.com/PyO3/maturin/archive/refs/tags/v${PV}.tar.gz + -> ${P}.gh.tar.gz + ${CARGO_CRATE_URIS} + test? ( $(cargo_crate_uris ${CRATES_TEST}) ) +" + +# note: rustls+ring is unused, so openssl license can be skipped +LICENSE="|| ( Apache-2.0 MIT ) doc? ( CC-BY-4.0 OFL-1.1 )" +LICENSE+=" + 0BSD Apache-2.0 Apache-2.0-with-LLVM-exceptions BSD ISC MIT MPL-2.0 + Unicode-DFS-2016 +" # crates +SLOT="0" +KEYWORDS="amd64 arm ~arm64 ~loong ~mips ppc ppc64 ~riscv ~s390 sparc x86" +IUSE="doc +ssl test" +RESTRICT="!test? ( test )" + +RDEPEND="$(python_gen_cond_dep 'dev-python/tomli[${PYTHON_USEDEP}]' 3.10)" +DEPEND="ssl? ( dev-libs/openssl:= )" +BDEPEND=" + virtual/pkgconfig + doc? ( app-text/mdbook ) + test? ( + ${RDEPEND} + $(python_gen_cond_dep 'dev-python/cffi[${PYTHON_USEDEP}]' 'python*') + dev-python/boltons[${PYTHON_USEDEP}] + dev-python/virtualenv[${PYTHON_USEDEP}] + dev-vcs/git + elibc_musl? ( dev-util/patchelf ) + ) +" +RDEPEND+=" ${DEPEND}" + +QA_FLAGS_IGNORED="usr/bin/${PN}" + +src_prepare() { + distutils-r1_src_prepare + + # we build the Rust executable (just once) via cargo_src_compile + sed -i -e '/setuptools_rust/d' -e '/rust_extensions/d' setup.py || die + + if use test; then + # used to prevent use of network during tests, and silence pip + # if it finds unrelated issues with system packages (bug #913613) + cat > "${T}"/pip.conf <<-EOF || die + [global] + quiet = 2 + + [install] + no-index = yes + no-dependencies = yes + EOF + + # used by *git_sdist_generator tests + git init -q || die + git config --global user.email "larry@gentoo.org" || die + git config --global user.name "Larry the Cow" || die + git add . || die + git commit -qm init || die + fi +} + +src_configure() { + export OPENSSL_NO_VENDOR=1 + + # bug #938847 (TODO?: should probably be an eclass default for musl) + use elibc_musl && RUSTFLAGS+=" -C target-feature=-crt-static" + + # https://github.com/rust-lang/stacker/issues/79 + use s390 && ! is-flagq '-march=*' && + append-cflags $(test-flags-CC -march=z10) + + local myfeatures=( + # like release.yml + native-tls for better platform support than rustls + full + password-storage + $(usev ssl native-tls) + ) + + cargo_src_configure --no-default-features +} + +python_compile_all() { + cargo_src_compile + + use !doc || mdbook build -d html guide || die + + if ! tc-is-cross-compiler; then + local maturin=$(cargo_target_dir)/maturin + "${maturin}" completions bash > "${T}"/${PN} || die + "${maturin}" completions fish > "${T}"/${PN}.fish || die + "${maturin}" completions zsh > "${T}"/_${PN} || die + else + ewarn "shell completion files were skipped due to cross-compilation" + fi +} + +python_test() { + local -x MATURIN_TEST_PYTHON=${EPYTHON} + local -x PIP_CONFIG_FILE=${T}/pip.conf + local -x VIRTUALENV_SYSTEM_SITE_PACKAGES=1 + + # need this for (new) python versions not yet recognized by pyo3 + local -x PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 + + local skip=( + # picky cli output test that easily benignly fail (bug #937992) + --skip cli_tests + # avoid need for wasm over a single hello world test + --skip integration_wasm_hello_world + # fragile depending on rust version, also wants libpypy*-c.so for pypy + --skip pyo3_no_extension_module + # unimportant tests that use uv, and it does not seem to be able + # to find the system's dev-python/uv (not worth the trouble) + --skip develop_hello_world::case_2 + --skip develop_pyo3_ffi_pure::case_2 + # fails on sparc since rust-1.74 (bug #934573), skip for now given + # should not affect the pep517 backend which is all we need on sparc + $(usev sparc '--skip build_context::test::test_macosx_deployment_target') + ) + + cargo_src_test -- "${skip[@]}" +} + +python_install_all() { + cargo_src_install + + dodoc Changelog.md README.md + use doc && dodoc -r guide/html + + if ! tc-is-cross-compiler; then + dobashcomp "${T}"/${PN} + dofishcomp "${T}"/${PN}.fish + dozshcomp "${T}"/_${PN} + fi +} diff --git a/sdk_container/src/third_party/portage-stable/dev-util/maturin/maturin-1.7.4.ebuild b/sdk_container/src/third_party/portage-stable/dev-util/maturin/maturin-1.7.4.ebuild new file mode 100644 index 00000000000..ce5b3ed2b42 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-util/maturin/maturin-1.7.4.ebuild @@ -0,0 +1,579 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +CRATES=" + adler2@2.0.0 + ahash@0.8.11 + aho-corasick@1.1.3 + allocator-api2@0.2.18 + anstream@0.6.14 + anstyle-parse@0.2.4 + anstyle-query@1.1.0 + anstyle-wincon@3.0.3 + anstyle@1.0.7 + anyhow@1.0.89 + autocfg@1.3.0 + automod@1.0.14 + base64@0.21.7 + base64@0.22.1 + bitflags@1.3.2 + bitflags@2.5.0 + block-buffer@0.10.4 + bstr@1.10.0 + byteorder@1.5.0 + bytesize@1.3.0 + bytes@1.7.1 + bzip2-sys@0.1.11+1.0.8 + bzip2@0.4.4 + cab@0.5.0 + camino@1.1.9 + cargo-config2@0.1.26 + cargo-options@0.7.4 + cargo-platform@0.1.8 + cargo-xwin@0.16.5 + cargo-zigbuild@0.19.3 + cargo_metadata@0.18.1 + cbindgen@0.26.0 + cc@1.1.21 + cfb@0.9.0 + cfg-if@1.0.0 + charset@0.1.5 + chumsky@0.9.3 + clap@4.5.7 + clap_builder@4.5.7 + clap_complete@4.5.5 + clap_complete_command@0.6.1 + clap_complete_nushell@4.5.2 + clap_derive@4.5.5 + clap_lex@0.7.1 + cli-table@0.4.7 + colorchoice@1.0.1 + configparser@3.1.0 + console@0.15.8 + content_inspector@0.2.4 + core-foundation-sys@0.8.6 + core-foundation@0.9.4 + cpufeatures@0.2.12 + crc32fast@1.4.2 + crc-catalog@2.4.0 + crc@3.2.1 + crossbeam-channel@0.5.13 + crossbeam-deque@0.8.5 + crossbeam-epoch@0.9.18 + crossbeam-utils@0.8.20 + crypto-common@0.1.6 + data-encoding@2.6.0 + deranged@0.3.11 + derivative@2.2.0 + dialoguer@0.11.0 + diff@0.1.13 + digest@0.10.7 + dirs-sys@0.4.1 + dirs@5.0.1 + dissimilar@1.0.9 + dunce@1.0.5 + dyn-clone@1.0.17 + either@1.13.0 + encode_unicode@0.3.6 + encoding_rs@0.8.34 + equivalent@1.0.1 + errno@0.3.9 + expect-test@1.5.0 + fastrand@2.1.0 + fat-macho@0.4.8 + filetime@0.2.23 + flate2@1.0.33 + fnv@1.0.7 + foreign-types-shared@0.1.1 + foreign-types@0.3.2 + form_urlencoded@1.2.1 + fs-err@2.11.0 + futures-channel@0.3.30 + futures-core@0.3.30 + futures-executor@0.3.30 + futures-io@0.3.30 + futures-macro@0.3.30 + futures-sink@0.3.30 + futures-task@0.3.30 + futures-timer@3.0.3 + futures-util@0.3.30 + futures@0.3.30 + generic-array@0.14.7 + getrandom@0.2.15 + globset@0.4.15 + glob@0.3.1 + goblin@0.8.2 + hashbrown@0.12.3 + hashbrown@0.14.5 + heck@0.4.1 + heck@0.5.0 + home@0.5.9 + humantime-serde@1.1.1 + humantime@2.1.0 + idna@0.5.0 + ignore@0.4.23 + indexmap@1.9.3 + indexmap@2.5.0 + indicatif@0.17.8 + indoc@2.0.5 + instant@0.1.13 + is_terminal_polyfill@1.70.0 + itertools@0.12.1 + itoa@1.0.11 + keyring@2.3.3 + lazy_static@1.4.0 + lddtree@0.3.5 + libc@0.2.158 + libmimalloc-sys@0.1.38 + libredox@0.1.3 + linux-keyutils@0.2.4 + linux-raw-sys@0.4.14 + lock_api@0.4.12 + log@0.4.21 + lzxd@0.2.5 + mailparse@0.15.0 + matchers@0.1.0 + memchr@2.7.2 + mimalloc@0.1.42 + mime@0.3.17 + mime_guess@2.0.4 + minijinja@1.0.21 + minimal-lexical@0.2.1 + miniz_oxide@0.8.0 + msi@0.7.0 + multipart@0.18.0 + native-tls@0.2.12 + nom@7.1.3 + normalize-line-endings@0.3.0 + normpath@1.2.0 + number_prefix@0.4.0 + num-conv@0.1.0 + nu-ansi-term@0.46.0 + once_cell@1.19.0 + openssl-macros@0.1.1 + openssl-probe@0.1.5 + openssl-sys@0.9.103 + openssl@0.10.66 + option-ext@0.2.0 + os_pipe@1.2.0 + overload@0.1.1 + parking_lot@0.12.3 + parking_lot_core@0.9.10 + paste@1.0.15 + path-slash@0.2.1 + pep440_rs@0.6.6 + pep508_rs@0.6.1 + percent-encoding@2.3.1 + pin-project-lite@0.2.14 + pin-utils@0.1.0 + pkg-config@0.3.30 + plain@0.2.3 + platform-info@2.0.3 + portable-atomic@1.6.0 + powerfmt@0.2.0 + ppv-lite86@0.2.17 + pretty_assertions@1.4.1 + proc-macro2@1.0.85 + proc-macro-crate@3.1.0 + psm@0.1.21 + pyproject-toml@0.11.0 + python-pkginfo@0.6.3 + quoted_printable@0.5.0 + quote@1.0.36 + rand@0.8.5 + rand_chacha@0.3.1 + rand_core@0.6.4 + rayon-core@1.12.1 + rayon@1.10.0 + redox_syscall@0.4.1 + redox_syscall@0.5.1 + redox_users@0.4.5 + regex-automata@0.1.10 + regex-automata@0.4.7 + regex-syntax@0.6.29 + regex-syntax@0.8.4 + regex@1.10.6 + relative-path@1.9.3 + rfc2047-decoder@1.0.5 + ring@0.17.8 + rstest@0.22.0 + rstest_macros@0.22.0 + rustc_version@0.4.1 + rustflags@0.1.6 + rustix@0.38.34 + rustls-pemfile@2.1.3 + rustls-pki-types@1.7.0 + rustls-webpki@0.102.4 + rustls@0.22.4 + rustversion@1.0.17 + ryu@1.0.18 + same-file@1.0.6 + schannel@0.1.23 + schemars@0.8.21 + schemars_derive@0.8.21 + scopeguard@1.2.0 + scroll@0.12.0 + scroll_derive@0.12.0 + security-framework-sys@2.11.0 + security-framework@2.11.0 + semver@1.0.23 + serde@1.0.210 + serde_derive@1.0.210 + serde_derive_internals@0.29.1 + serde_json@1.0.128 + serde_spanned@0.6.6 + sha2@0.10.8 + sharded-slab@0.1.7 + shell-words@1.1.0 + shlex@1.3.0 + similar@2.5.0 + slab@0.4.9 + smallvec@1.13.2 + smawk@0.3.2 + snapbox-macros@0.3.10 + snapbox@0.6.16 + socks@0.3.4 + spin@0.9.8 + stacker@0.1.15 + static_assertions@1.1.0 + strsim@0.11.1 + subtle@2.5.0 + syn@1.0.109 + syn@2.0.76 + target-lexicon@0.12.16 + tar@0.4.42 + tempfile@3.11.0 + termcolor@1.4.1 + terminal_size@0.3.0 + textwrap@0.16.1 + thiserror-impl@1.0.64 + thiserror@1.0.64 + thread_local@1.1.8 + time-core@0.1.2 + time-macros@0.2.18 + time@0.3.36 + tinyvec@1.7.0 + tinyvec_macros@0.1.1 + toml@0.5.11 + toml@0.8.15 + toml_datetime@0.6.6 + toml_edit@0.21.1 + toml_edit@0.22.16 + tracing-attributes@0.1.27 + tracing-core@0.1.32 + tracing-log@0.2.0 + tracing-serde@0.1.3 + tracing-subscriber@0.3.18 + tracing@0.1.40 + trycmd@0.15.6 + twox-hash@1.6.3 + typenum@1.17.0 + unicase@2.7.0 + unicode-bidi@0.3.15 + unicode-ident@1.0.12 + unicode-linebreak@0.1.5 + unicode-normalization@0.1.23 + unicode-width@0.1.13 + unicode-xid@0.2.6 + unscanny@0.1.0 + untrusted@0.9.0 + ureq@2.9.7 + urlencoding@2.1.3 + url@2.5.2 + utf8parse@0.2.2 + uuid@1.8.0 + valuable@0.1.0 + vcpkg@0.2.15 + versions@6.2.0 + version_check@0.9.4 + wait-timeout@0.2.0 + walkdir@2.5.0 + wasi@0.11.0+wasi-snapshot-preview1 + webpki-roots@0.26.2 + which@5.0.0 + which@6.0.3 + wild@2.2.1 + winapi-i686-pc-windows-gnu@0.4.0 + winapi-util@0.1.8 + winapi-x86_64-pc-windows-gnu@0.4.0 + winapi@0.3.9 + windows-sys@0.48.0 + windows-sys@0.52.0 + windows-targets@0.48.5 + windows-targets@0.52.5 + windows_aarch64_gnullvm@0.48.5 + windows_aarch64_gnullvm@0.52.5 + windows_aarch64_msvc@0.48.5 + windows_aarch64_msvc@0.52.5 + windows_i686_gnullvm@0.52.5 + windows_i686_gnu@0.48.5 + windows_i686_gnu@0.52.5 + windows_i686_msvc@0.48.5 + windows_i686_msvc@0.52.5 + windows_x86_64_gnullvm@0.48.5 + windows_x86_64_gnullvm@0.52.5 + windows_x86_64_gnu@0.48.5 + windows_x86_64_gnu@0.52.5 + windows_x86_64_msvc@0.48.5 + windows_x86_64_msvc@0.52.5 + winnow@0.5.40 + winnow@0.6.13 + winsafe@0.0.19 + xattr@1.3.1 + xwin@0.5.1 + yansi@1.0.1 + zerocopy-derive@0.7.34 + zerocopy@0.7.34 + zeroize@1.8.1 + zip@0.6.6 +" +# additional crates used by test-crates/* test packages, +# `grep test-crates tests/run.rs` to see which are needed +CRATES_TEST=" + anstream@0.6.15 + anstyle-parse@0.2.5 + anstyle-query@1.1.1 + anstyle-wincon@3.0.4 + anstyle@1.0.8 + anyhow@1.0.86 + askama@0.12.1 + askama_derive@0.12.5 + askama_escape@0.10.3 + askama_parser@0.2.1 + autocfg@1.1.0 + basic-toml@0.1.9 + bincode@1.3.3 + bytes@1.6.0 + camino@1.1.7 + cargo_metadata@0.15.4 + cc@1.0.73 + cc@1.0.81 + cc@1.0.83 + clap@4.5.16 + clap_builder@4.5.15 + clap_derive@4.5.13 + clap_lex@0.7.2 + colorchoice@1.0.2 + getrandom@0.2.10 + indoc@2.0.4 + is_terminal_polyfill@1.70.1 + libc@0.2.134 + libc@0.2.147 + libc@0.2.149 + libc@0.2.155 + log@0.4.22 + memchr@2.7.4 + memoffset@0.9.0 + memoffset@0.9.1 + mime_guess@2.0.5 + once_cell@1.15.0 + once_cell@1.18.0 + portable-atomic@1.7.0 + proc-macro2@1.0.86 + pyo3-build-config@0.18.3 + pyo3-build-config@0.22.0 + pyo3-build-config@0.22.2 + pyo3-ffi@0.18.3 + pyo3-ffi@0.22.0 + pyo3-ffi@0.22.2 + pyo3-macros-backend@0.22.0 + pyo3-macros-backend@0.22.2 + pyo3-macros@0.22.0 + pyo3-macros@0.22.2 + pyo3@0.22.0 + pyo3@0.22.2 + python3-dll-a@0.2.6 + python3-dll-a@0.2.9 + serde@1.0.203 + serde@1.0.209 + serde_derive@1.0.203 + serde_derive@1.0.209 + serde_json@1.0.118 + serde_json@1.0.127 + siphasher@0.3.11 + syn@2.0.68 + syn@2.0.72 + target-lexicon@0.12.11 + target-lexicon@0.12.14 + thiserror-impl@1.0.61 + thiserror-impl@1.0.63 + thiserror@1.0.61 + thiserror@1.0.63 + unicode-ident@1.0.5 + unicode-ident@1.0.11 + uniffi@0.28.0 + uniffi@0.28.1 + uniffi_bindgen@0.28.0 + uniffi_bindgen@0.28.1 + uniffi_build@0.28.0 + uniffi_build@0.28.1 + uniffi_checksum_derive@0.28.0 + uniffi_checksum_derive@0.28.1 + uniffi_core@0.28.0 + uniffi_core@0.28.1 + uniffi_macros@0.28.0 + uniffi_macros@0.28.1 + uniffi_meta@0.28.0 + uniffi_meta@0.28.1 + uniffi_testing@0.28.0 + uniffi_testing@0.28.1 + uniffi_udl@0.28.0 + uniffi_udl@0.28.1 + unindent@0.2.3 + version_check@0.9.5 + weedle2@5.0.0 + windows-targets@0.52.6 + windows_aarch64_gnullvm@0.52.6 + windows_aarch64_msvc@0.52.6 + windows_i686_gnullvm@0.52.6 + windows_i686_gnu@0.52.6 + windows_i686_msvc@0.52.6 + windows_x86_64_gnullvm@0.52.6 + windows_x86_64_gnu@0.52.6 + windows_x86_64_msvc@0.52.6 +" +DISTUTILS_USE_PEP517=setuptools +PYTHON_COMPAT=( pypy3 python3_{10..13} ) +inherit cargo distutils-r1 flag-o-matic shell-completion toolchain-funcs + +DESCRIPTION="Build and publish crates with pyo3, rust-cpython and cffi bindings" +HOMEPAGE="https://www.maturin.rs/" +SRC_URI=" + https://github.com/PyO3/maturin/archive/refs/tags/v${PV}.tar.gz + -> ${P}.gh.tar.gz + ${CARGO_CRATE_URIS} + test? ( $(cargo_crate_uris ${CRATES_TEST}) ) +" + +# note: rustls+ring is unused, so openssl license can be skipped +LICENSE="|| ( Apache-2.0 MIT ) doc? ( CC-BY-4.0 OFL-1.1 )" +LICENSE+=" + 0BSD Apache-2.0 Apache-2.0-with-LLVM-exceptions BSD ISC MIT MPL-2.0 + Unicode-DFS-2016 +" # crates +SLOT="0" +KEYWORDS="~amd64 ~arm ~arm64 ~loong ~mips ~ppc ~ppc64 ~riscv ~s390 ~sparc ~x86" +IUSE="doc +ssl test" +RESTRICT="!test? ( test )" + +RDEPEND="$(python_gen_cond_dep 'dev-python/tomli[${PYTHON_USEDEP}]' 3.10)" +DEPEND="ssl? ( dev-libs/openssl:= )" +BDEPEND=" + virtual/pkgconfig + doc? ( app-text/mdbook ) + test? ( + ${RDEPEND} + $(python_gen_cond_dep 'dev-python/cffi[${PYTHON_USEDEP}]' 'python*') + dev-python/boltons[${PYTHON_USEDEP}] + dev-python/virtualenv[${PYTHON_USEDEP}] + dev-vcs/git + elibc_musl? ( dev-util/patchelf ) + ) +" +RDEPEND+=" ${DEPEND}" + +QA_FLAGS_IGNORED="usr/bin/${PN}" + +src_prepare() { + distutils-r1_src_prepare + + # we build the Rust executable (just once) via cargo_src_compile + sed -i -e '/setuptools_rust/d' -e '/rust_extensions/d' setup.py || die + + if use test; then + # used to prevent use of network during tests, and silence pip + # if it finds unrelated issues with system packages (bug #913613) + cat > "${T}"/pip.conf <<-EOF || die + [global] + quiet = 2 + + [install] + no-index = yes + no-dependencies = yes + EOF + + # used by *git_sdist_generator tests + git init -q || die + git config --global user.email "larry@gentoo.org" || die + git config --global user.name "Larry the Cow" || die + git add . || die + git commit -qm init || die + fi +} + +src_configure() { + export OPENSSL_NO_VENDOR=1 + + # bug #938847 (TODO?: should probably be an eclass default for musl) + use elibc_musl && RUSTFLAGS+=" -C target-feature=-crt-static" + + # https://github.com/rust-lang/stacker/issues/79 + use s390 && ! is-flagq '-march=*' && + append-cflags $(test-flags-CC -march=z10) + + local myfeatures=( + # like release.yml + native-tls for better platform support than rustls + full + password-storage + $(usev ssl native-tls) + ) + + cargo_src_configure --no-default-features +} + +python_compile_all() { + cargo_src_compile + + use !doc || mdbook build -d html guide || die + + if ! tc-is-cross-compiler; then + local maturin=$(cargo_target_dir)/maturin + "${maturin}" completions bash > "${T}"/${PN} || die + "${maturin}" completions fish > "${T}"/${PN}.fish || die + "${maturin}" completions zsh > "${T}"/_${PN} || die + else + ewarn "shell completion files were skipped due to cross-compilation" + fi +} + +python_test() { + local -x MATURIN_TEST_PYTHON=${EPYTHON} + local -x PIP_CONFIG_FILE=${T}/pip.conf + local -x VIRTUALENV_SYSTEM_SITE_PACKAGES=1 + + # need this for (new) python versions not yet recognized by pyo3 + local -x PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 + + local skip=( + # picky cli output test that easily benignly fail (bug #937992) + --skip cli_tests + # avoid need for wasm over a single hello world test + --skip integration_wasm_hello_world + # fragile depending on rust version, also wants libpypy*-c.so for pypy + --skip pyo3_no_extension_module + # unimportant tests that use uv, and it does not seem to be able + # to find the system's dev-python/uv (not worth the trouble) + --skip develop_hello_world::case_2 + --skip develop_pyo3_ffi_pure::case_2 + # fails on sparc since rust-1.74 (bug #934573), skip for now given + # should not affect the pep517 backend which is all we need on sparc + $(usev sparc '--skip build_context::test::test_macosx_deployment_target') + ) + + cargo_src_test -- "${skip[@]}" +} + +python_install_all() { + cargo_src_install + + dodoc Changelog.md README.md + use doc && dodoc -r guide/html + + if ! tc-is-cross-compiler; then + dobashcomp "${T}"/${PN} + dofishcomp "${T}"/${PN}.fish + dozshcomp "${T}"/_${PN} + fi +} diff --git a/sdk_container/src/third_party/portage-stable/dev-util/maturin/metadata.xml b/sdk_container/src/third_party/portage-stable/dev-util/maturin/metadata.xml new file mode 100644 index 00000000000..8f5c9c78ca0 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/dev-util/maturin/metadata.xml @@ -0,0 +1,13 @@ + + + + + ionen@gentoo.org + Ionen Wolkens + + + https://www.maturin.rs/changelog.html + PyO3/maturin + maturin + + diff --git a/sdk_container/src/third_party/portage-stable/eclass/shell-completion.eclass b/sdk_container/src/third_party/portage-stable/eclass/shell-completion.eclass new file mode 100644 index 00000000000..d582028847b --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/eclass/shell-completion.eclass @@ -0,0 +1,115 @@ +# Copyright 2023 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# @ECLASS: shell-completion.eclass +# @MAINTAINER: +# Jonas Frei +# Florian Schmaus +# @AUTHOR: +# Alfred Wingate +# @SUPPORTED_EAPIS: 8 +# @PROVIDES: bash-completion-r1 +# @BLURB: a few quick functions to install various shell completion files +# @DESCRIPTION: +# This eclass provides a standardised way to install shell completions +# for popular shells. It inherits the already widely adopted +# 'bash-completion-r1', thus extending on its functionality. + +case ${EAPI} in + 8) ;; + *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" +esac + +if [[ ! ${_SHELL_COMPLETION_ECLASS} ]]; then +_SHELL_COMPLETION_ECLASS=1 + +# Extend bash-completion-r1 +inherit bash-completion-r1 + +# @FUNCTION: _shell-completion_get_fishcompdir +# @INTERNAL +# @RETURN: unprefixed fish completions directory +_shell-completion_get_fishcompdir() { + echo "/usr/share/fish/vendor_completions.d" +} + +# @FUNCTION: _shell-completion_get_zshcompdir +# @INTERNAL +# @RETURN: unprefixed zsh completions directory +_shell-completion_get_zshcompdir() { + echo "/usr/share/zsh/site-functions" +} + +# @FUNCTION: get_fishcompdir +# @RETURN: the fish completions directory (with EPREFIX) +get_fishcompdir() { + debug-print-function ${FUNCNAME} "${@}" + + echo "${EPREFIX}$(_shell-completion_get_fishcompdir)" +} + +# @FUNCTION: get_zshcompdir +# @RETURN: the zsh completions directory (with EPREFIX) +get_zshcompdir() { + debug-print-function ${FUNCNAME} "${@}" + + echo "${EPREFIX}$(_shell-completion_get_zshcompdir)" +} + +# @FUNCTION: dofishcomp +# @USAGE: +# @DESCRIPTION: +# Install fish completion files passed as args. +dofishcomp() { + debug-print-function ${FUNCNAME} "${@}" + + ( + insopts -m 0644 + insinto "$(_shell-completion_get_fishcompdir)" + doins "${@}" + ) +} + +# @FUNCTION: dozshcomp +# @USAGE: +# @DESCRIPTION: +# Install zsh completion files passed as args. +dozshcomp() { + debug-print-function ${FUNCNAME} "${@}" + + ( + insopts -m 0644 + insinto "$(_shell-completion_get_zshcompdir)" + doins "${@}" + ) +} + +# @FUNCTION: newfishcomp +# @USAGE: +# @DESCRIPTION: +# Install fish file under a new name. +newfishcomp() { + debug-print-function ${FUNCNAME} "${@}" + + ( + insopts -m 0644 + insinto "$(_shell-completion_get_fishcompdir)" + newins "${@}" + ) +} + +# @FUNCTION: newzshcomp +# @USAGE: +# @DESCRIPTION: +# Install zsh file under a new name. +newzshcomp() { + debug-print-function ${FUNCNAME} "${@}" + + ( + insopts -m 0644 + insinto "$(_shell-completion_get_zshcompdir)" + newins "${@}" + ) +} + +fi