From 46cdbd4966d82e04e63780a650add0a2adc31a64 Mon Sep 17 00:00:00 2001 From: Balint Reczey Date: Fri, 6 Mar 2020 17:59:20 +0100 Subject: [PATCH] New upstream version 245 --- .github/FUNDING.yml | 2 +- .github/ISSUE_TEMPLATE/Bug_report.md | 2 +- .lgtm.yml | 13 +- .mailmap | 2 + .mkosi/mkosi.fedora | 17 +- NEWS | 357 +- README.md | 4 +- TODO | 200 +- configure | 3 +- docs/.gitignore | 1 + docs/AUTOMATIC_BOOT_ASSESSMENT.md | 8 +- docs/BLOCK_DEVICE_LOCKING.md | 2 + docs/BOOT_LOADER_INTERFACE.md | 12 +- docs/BOOT_LOADER_SPECIFICATION.md | 40 +- docs/CGROUP_DELEGATION.md | 10 +- docs/CODE_OF_CONDUCT.md | 4 +- docs/CODE_QUALITY.md | 2 + docs/CODING_STYLE.md | 4 +- docs/CONTAINER_INTERFACE.md | 290 ++ docs/CONTRIBUTING.md | 2 + docs/DISCOVERABLE_PARTITIONS.md | 216 + docs/DISTRO_PORTING.md | 2 + docs/ENVIRONMENT.md | 9 + docs/GROUP_RECORD.md | 158 + docs/HACKING.md | 8 +- docs/HOME_DIRECTORY.md | 173 + docs/INITRD_INTERFACE.md | 73 + docs/PORTABILITY_AND_STABILITY.md | 162 + docs/PORTABLE_SERVICES.md | 4 +- docs/PREDICTABLE_INTERFACE_NAMES.md | 27 +- docs/RANDOM_SEEDS.md | 2 + docs/RELEASE.md | 2 + docs/ROOT_STORAGE_DAEMONS.md | 193 + docs/SECURITY.md | 6 +- docs/TEMPORARY_DIRECTORIES.md | 2 + docs/TESTING_WITH_SANITIZERS.md | 6 +- docs/TRANSIENT-SETTINGS.md | 7 +- docs/TRANSLATORS.md | 4 +- docs/UIDS-GIDS.md | 21 +- docs/USER_GROUP_API.md | 267 ++ docs/USER_RECORD.md | 1023 +++++ docs/_config.yml | 10 +- docs/_data/extra_pages.json | 10 + docs/_includes/footer.html | 5 + docs/_includes/head.html | 16 + docs/_includes/header.html | 11 + docs/_layouts/default.html | 18 + docs/assets/page-logo.svg | 6 + docs/favicon.png | Bin 0 -> 394 bytes docs/favicon.svg | 10 + docs/fonts/heebo-bold.woff | Bin 0 -> 42844 bytes docs/fonts/heebo-regular.woff | Bin 0 -> 42672 bytes docs/index.md | 94 +- docs/style.css | 347 ++ factory/etc/nsswitch.conf | 2 +- factory/etc/pam.d/system-auth | 26 +- fuzzbuzz.yaml | 1 + hwdb.d/20-OUI.hwdb | 719 +++- hwdb.d/20-acpi-vendor.hwdb | 3 + hwdb.d/20-acpi-vendor.hwdb.patch | 98 +- hwdb.d/20-pci-vendor-model.hwdb | 344 +- hwdb.d/20-usb-vendor-model.hwdb | 179 +- hwdb.d/60-keyboard.hwdb | 29 +- hwdb.d/60-sensor.hwdb | 20 +- hwdb.d/acpi_id_registry.html | 1 + hwdb.d/ma-large.txt | 1410 +++++-- hwdb.d/ma-medium.txt | 273 +- hwdb.d/ma-small.txt | 600 ++- hwdb.d/meson.build | 1 + hwdb.d/parse_hwdb.py | 1 + hwdb.d/pci.ids | 126 +- hwdb.d/usb.ids | 69 +- man/busctl.xml | 9 + man/crypttab.xml | 64 +- man/environment.d.xml | 35 +- man/halt.xml | 20 +- man/homectl.xml | 833 ++++ man/journalctl.xml | 22 + man/journald.conf.xml | 101 +- man/kernel-command-line.xml | 13 +- man/machinectl.xml | 17 +- man/networkctl.xml | 25 + man/nss-systemd.xml | 22 +- man/pam_systemd.xml | 44 +- man/pam_systemd_home.xml | 131 + man/portablectl.xml | 28 +- man/repart.d.xml | 388 ++ man/resolved.conf.xml | 3 + man/rules/meson.build | 44 +- man/sd-bus.xml | 1 + man/sd_bus_enqueue_for_read.xml | 88 + man/sd_bus_message_dump.xml | 107 + man/sd_bus_message_read.xml | 18 +- man/sd_bus_message_read_array.xml | 8 +- man/sd_bus_message_read_basic.xml | 54 +- man/sd_bus_message_sensitive.xml | 85 + man/sd_event_add_child.xml | 162 +- man/sd_event_add_signal.xml | 17 +- man/sd_journal_open.xml | 22 + man/sd_journal_print.xml | 2 +- man/standard-conf.xml | 78 +- man/supported-controllers.xml | 14 + man/sysctl.d.xml | 76 +- man/systemctl.xml | 24 +- man/systemd-bless-boot.service.xml | 1 + ...systemd-boot-check-no-failures.service.xml | 1 + man/systemd-boot.xml | 2 +- man/systemd-fstab-generator.xml | 10 +- man/systemd-getty-generator.xml | 35 +- man/systemd-gpt-auto-generator.xml | 81 +- man/systemd-homed.service.xml | 57 + man/systemd-id128.xml | 6 +- man/systemd-journald.service.xml | 55 +- man/systemd-machine-id-setup.xml | 9 +- man/systemd-makefs@.service.xml | 1 + man/systemd-mount.xml | 10 + man/systemd-network-generator.service.xml | 103 + man/systemd-networkd-wait-online.service.xml | 18 +- man/systemd-networkd.service.xml | 8 +- man/systemd-nspawn.xml | 17 +- ...-pstore.xml => systemd-pstore.service.xml} | 16 +- man/systemd-repart.xml | 269 ++ man/systemd-system.conf.xml | 32 +- man/systemd-userdbd.service.xml | 69 + man/systemd.exec.xml | 165 +- man/systemd.journal-fields.xml | 19 + man/systemd.link.xml | 116 +- man/systemd.mount.xml | 41 +- man/systemd.net-naming-scheme.xml | 27 +- man/systemd.netdev.xml | 16 +- man/systemd.network.xml | 756 +++- man/systemd.path.xml | 9 + man/systemd.resource-control.xml | 113 +- man/systemd.scope.xml | 9 + man/systemd.special.xml | 43 +- man/systemd.syntax.xml | 9 + man/systemd.timer.xml | 24 +- man/systemd.unit.xml | 44 +- man/systemd.xml | 28 +- man/sysusers.d.xml | 31 +- man/tmpfiles.d.xml | 16 +- man/udev.xml | 4 + man/user@.service.xml | 4 +- man/userdbctl.xml | 258 ++ man/yubikey-crypttab.sh | 47 + meson.build | 256 +- meson_options.txt | 16 + network/99-default.link | 1 + po/POTFILES.in | 1 + po/be.po | 46 +- po/be@latin.po | 46 +- po/bg.po | 46 +- po/ca.po | 54 +- po/cs.po | 180 +- po/da.po | 46 +- po/de.po | 46 +- po/el.po | 46 +- po/es.po | 46 +- po/fr.po | 314 +- po/gl.po | 651 ++- po/hr.po | 46 +- po/hu.po | 46 +- po/id.po | 54 +- po/it.po | 306 +- po/ja.po | 153 +- po/ko.po | 46 +- po/lt.po | 54 +- po/pl.po | 178 +- po/pt_BR.po | 54 +- po/ro.po | 46 +- po/ru.po | 406 +- po/sk.po | 46 +- po/sr.po | 54 +- po/sv.po | 54 +- po/tr.po | 54 +- po/uk.po | 202 +- po/zh_CN.po | 46 +- po/zh_TW.po | 54 +- presets/90-systemd.preset | 2 + rules.d/60-evdev.rules | 14 +- rules.d/60-fido-id.rules | 6 + semaphoreci/semaphore-runner.sh | 4 +- shell-completion/bash/busctl | 6 +- shell-completion/bash/journalctl | 2 +- shell-completion/bash/loginctl | 2 +- shell-completion/bash/machinectl | 2 +- shell-completion/bash/networkctl | 6 +- shell-completion/bash/portablectl | 4 +- shell-completion/bash/systemctl.in | 11 +- shell-completion/bash/systemd-analyze | 26 +- shell-completion/bash/systemd-cgls | 2 +- shell-completion/bash/systemd-cgtop | 2 +- shell-completion/bash/systemd-nspawn | 2 +- shell-completion/bash/systemd-run | 2 +- shell-completion/bash/timedatectl | 2 +- shell-completion/zsh/_systemctl.in | 82 +- src/activate/activate.c | 1 + src/analyze/analyze-security.c | 63 +- src/analyze/analyze.c | 189 +- src/basic/blockdev-util.c | 32 +- src/basic/capability-util.c | 28 +- src/basic/copy.c | 60 +- src/basic/copy.h | 1 + src/basic/efivars.c | 13 +- src/basic/errno-util.h | 8 + src/basic/escape.c | 20 +- src/basic/escape.h | 15 +- src/basic/extract-word.c | 2 +- src/basic/fileio.c | 124 +- src/basic/fileio.h | 7 +- src/basic/format-util.h | 39 +- src/basic/fs-util.c | 93 +- src/basic/fs-util.h | 1 + src/basic/in-addr-util.c | 46 - src/basic/in-addr-util.h | 2 +- src/basic/linux/btrfs.h | 18 +- src/basic/linux/btrfs_tree.h | 32 +- src/basic/linux/can/vxcan.h | 2 +- src/basic/linux/if.h | 1 + src/basic/linux/if_bridge.h | 1 + src/basic/linux/if_ether.h | 1 + src/basic/linux/if_link.h | 8 + src/basic/linux/nexthop.h | 62 +- src/basic/linux/pkt_sched.h | 1364 +++---- src/basic/linux/rtnetlink.h | 25 +- src/basic/linux/update.sh | 2 +- src/basic/linux/wireguard.h | 40 +- src/basic/locale-util.c | 43 +- src/basic/locale-util.h | 8 +- src/basic/macro.h | 23 + src/basic/memory-util.h | 20 +- src/basic/meson.build | 2 + src/basic/missing_magic.h | 5 + src/basic/missing_syscall.h | 44 + src/basic/missing_xfs.h | 42 + src/basic/nss-util.h | 32 + src/basic/ordered-set.h | 4 + src/basic/parse-util.c | 74 +- src/basic/parse-util.h | 5 +- src/basic/path-util.c | 10 + src/basic/path-util.h | 14 +- src/basic/process-util.c | 96 + src/basic/process-util.h | 32 +- src/basic/quota-util.c | 41 + src/basic/quota-util.h | 19 + src/basic/random-util.c | 14 +- src/basic/selinux-util.c | 33 +- src/basic/selinux-util.h | 8 + src/basic/signal-util.c | 15 + src/basic/signal-util.h | 2 + src/basic/socket-label.c | 28 - src/basic/socket-util.c | 269 +- src/basic/socket-util.h | 19 +- src/basic/special.h | 1 + src/basic/string-table.h | 2 +- src/basic/string-util.c | 130 + src/basic/string-util.h | 5 + src/basic/strv.c | 123 +- src/basic/strv.h | 38 +- src/basic/syslog-util.c | 33 + src/basic/syslog-util.h | 2 + src/basic/tmpfile-util.c | 52 +- src/basic/unit-name.c | 2 +- src/basic/unit-name.h | 1 + src/basic/user-util.c | 148 +- src/basic/user-util.h | 22 +- src/basic/virt.c | 85 +- src/boot/bootctl.c | 26 +- src/boot/efi/boot.c | 58 +- src/boot/efi/stub.c | 8 +- src/boot/efi/util.c | 2 +- src/busctl/busctl.c | 52 +- src/core/automount.c | 6 +- src/core/bpf-devices.c | 56 +- src/core/cgroup.c | 47 +- src/core/core-varlink.c | 310 ++ src/core/core-varlink.h | 7 + src/core/dbus-execute.c | 41 +- src/core/dbus-job.c | 1 + src/core/dbus-manager.c | 5 +- src/core/dbus-socket.c | 1 + src/core/dbus-swap.c | 11 +- src/core/dbus-unit.c | 1 + src/core/dbus-util.h | 3 +- src/core/dbus.c | 140 +- src/core/dbus.h | 2 - src/core/device.c | 1 + src/core/dynamic-user.c | 8 +- src/core/execute.c | 289 +- src/core/execute.h | 3 + src/core/job.c | 70 +- src/core/job.h | 3 +- src/core/killall.c | 2 +- src/core/load-dropin.c | 23 +- src/core/load-fragment-gperf.gperf.m4 | 4 +- src/core/load-fragment.c | 96 +- src/core/load-fragment.h | 2 + src/core/main.c | 56 +- src/core/manager.c | 94 +- src/core/manager.h | 10 +- src/core/meson.build | 4 +- src/core/mount-setup.c | 2 +- src/core/mount.c | 46 +- src/core/namespace.c | 121 +- src/core/namespace.h | 1 + src/core/path.c | 2 + src/core/scope.c | 1 + src/core/selinux-access.c | 69 +- src/core/selinux-access.h | 1 - src/core/service.c | 30 +- src/core/show-status.c | 1 + src/core/show-status.h | 12 +- src/core/socket.c | 3 + src/core/swap.c | 65 +- src/core/timer.c | 6 +- src/core/transaction.c | 12 +- src/core/unit.c | 250 +- src/core/unit.h | 26 +- src/cryptsetup/cryptsetup-generator.c | 77 +- src/cryptsetup/cryptsetup-pkcs11.c | 196 + src/cryptsetup/cryptsetup-pkcs11.h | 37 + src/cryptsetup/cryptsetup.c | 191 +- src/debug-generator/debug-generator.c | 10 +- src/dissect/dissect.c | 21 +- src/firstboot/firstboot.c | 24 +- src/fstab-generator/fstab-generator.c | 90 +- src/fuzz/fuzz-bus-message.c | 2 +- src/fuzz/fuzz-json.c | 2 +- src/gpt-auto-generator/gpt-auto-generator.c | 409 +- .../hibernate-resume-generator.c | 2 +- src/home/home-util.c | 160 + src/home/home-util.h | 24 + src/home/homectl.c | 3607 +++++++++++++++++ src/home/homed-bus.c | 64 + src/home/homed-bus.h | 10 + src/home/homed-home-bus.c | 877 ++++ src/home/homed-home-bus.h | 36 + src/home/homed-home.c | 2712 +++++++++++++ src/home/homed-home.h | 168 + src/home/homed-manager-bus.c | 690 ++++ src/home/homed-manager-bus.h | 6 + src/home/homed-manager.c | 1671 ++++++++ src/home/homed-manager.h | 67 + src/home/homed-operation.c | 76 + src/home/homed-operation.h | 62 + src/home/homed-varlink.c | 370 ++ src/home/homed-varlink.h | 8 + src/home/homed.c | 46 + src/home/homework-cifs.c | 214 + src/home/homework-cifs.h | 11 + src/home/homework-directory.c | 242 ++ src/home/homework-directory.h | 10 + src/home/homework-fscrypt.c | 644 +++ src/home/homework-fscrypt.h | 10 + src/home/homework-luks.c | 2954 ++++++++++++++ src/home/homework-luks.h | 38 + src/home/homework-mount.c | 96 + src/home/homework-mount.h | 8 + src/home/homework-pkcs11.c | 104 + src/home/homework-pkcs11.h | 21 + src/home/homework-quota.c | 124 + src/home/homework-quota.h | 8 + src/home/homework.c | 1482 +++++++ src/home/homework.h | 57 + src/home/meson.build | 81 + src/home/org.freedesktop.home1.conf | 193 + src/home/org.freedesktop.home1.policy | 72 + src/home/org.freedesktop.home1.service | 7 + src/home/pam_systemd_home.c | 951 +++++ src/home/pam_systemd_home.sym | 12 + src/home/pwquality-util.c | 186 + src/home/pwquality-util.h | 9 + src/home/user-record-sign.c | 174 + src/home/user-record-sign.h | 19 + src/home/user-record-util.c | 1227 ++++++ src/home/user-record-util.h | 58 + src/id128/id128.c | 86 +- src/import/curl-util.c | 9 + src/import/import-raw.c | 10 +- src/import/pull-raw.c | 20 +- src/initctl/initctl.c | 2 +- src/journal-remote/journal-remote-main.c | 1 + src/journal-remote/journal-upload-journal.c | 2 +- src/journal-remote/journal-upload.c | 8 +- src/journal-remote/journal-upload.h | 1 + src/journal/journal-file.c | 4 +- src/journal/journal-file.h | 1 + src/journal/journal-internal.h | 1 + src/journal/journalctl.c | 270 +- src/journal/journald-context.c | 51 +- src/journal/journald-kmsg.c | 26 +- src/journal/journald-native.c | 18 +- src/journal/journald-native.h | 2 +- src/journal/journald-rate-limit.c | 2 +- src/journal/journald-server.c | 658 ++- src/journal/journald-server.h | 12 +- src/journal/journald-stream.c | 59 +- src/journal/journald-stream.h | 2 +- src/journal/journald-syslog.c | 45 +- src/journal/journald-syslog.h | 2 +- src/journal/journald.c | 25 +- src/journal/sd-journal.c | 146 +- src/kernel-install/00-entry-directory.install | 2 +- src/kernel-install/50-depmod.install | 2 +- src/kernel-install/90-loaderentry.install | 3 +- src/kernel-install/kernel-install | 2 +- src/libsystemd-network/network-internal.c | 55 +- src/libsystemd-network/network-internal.h | 5 + src/libsystemd-network/sd-dhcp-client.c | 44 +- src/libsystemd-network/sd-dhcp-server.c | 2 +- src/libsystemd-network/sd-dhcp6-client.c | 14 +- src/libsystemd/libsystemd.sym | 15 + src/libsystemd/sd-bus/bus-common-errors.c | 31 + src/libsystemd/sd-bus/bus-common-errors.h | 32 + src/libsystemd/sd-bus/bus-dump.c | 18 +- src/libsystemd/sd-bus/bus-dump.h | 7 - src/libsystemd/sd-bus/bus-message.c | 37 +- src/libsystemd/sd-bus/bus-message.h | 2 +- src/libsystemd/sd-bus/bus-objects.c | 33 + src/libsystemd/sd-bus/sd-bus.c | 4 +- src/libsystemd/sd-bus/test-bus-chat.c | 2 +- src/libsystemd/sd-bus/test-bus-gvariant.c | 6 +- src/libsystemd/sd-bus/test-bus-marshal.c | 10 +- src/libsystemd/sd-bus/test-bus-objects.c | 16 +- src/libsystemd/sd-bus/test-bus-watch-bind.c | 12 +- src/libsystemd/sd-daemon/sd-daemon.c | 12 +- src/libsystemd/sd-device/sd-device.c | 16 +- src/libsystemd/sd-device/test-sd-device.c | 24 +- src/libsystemd/sd-event/event-source.h | 8 +- src/libsystemd/sd-event/sd-event.c | 531 ++- src/libsystemd/sd-event/test-event.c | 124 +- src/libsystemd/sd-hwdb/hwdb-util.c | 40 +- src/libsystemd/sd-id128/id128-util.c | 15 +- src/libsystemd/sd-id128/id128-util.h | 6 +- src/libsystemd/sd-id128/sd-id128.c | 17 +- src/libsystemd/sd-login/sd-login.c | 3 +- src/libsystemd/sd-netlink/netlink-message.c | 195 +- src/libsystemd/sd-netlink/netlink-types.c | 110 +- src/libsystemd/sd-netlink/netlink-types.h | 13 + src/libsystemd/sd-netlink/netlink-util.c | 200 + src/libsystemd/sd-netlink/netlink-util.h | 11 +- src/libsystemd/sd-netlink/rtnl-message.c | 2 + src/libsystemd/sd-netlink/sd-netlink.c | 4 + src/libsystemd/sd-netlink/test-netlink.c | 31 + src/libsystemd/sd-network/network-util.c | 47 + src/libsystemd/sd-network/network-util.h | 11 + src/libsystemd/sd-network/sd-network.c | 11 +- src/login/inhibit.c | 2 +- src/login/loginctl.c | 8 +- src/login/logind-core.c | 39 +- src/login/logind-dbus.c | 26 +- src/login/logind-seat-dbus.c | 58 +- src/login/logind-seat.c | 8 +- src/login/logind-session-dbus.c | 36 +- src/login/logind-session.c | 23 +- src/login/logind-user-dbus.c | 68 +- src/login/logind-user.c | 173 +- src/login/logind-user.h | 10 +- src/login/logind.h | 5 +- src/login/org.freedesktop.login1.policy | 56 +- src/login/pam_systemd.c | 463 ++- src/login/user-runtime-dir.c | 3 + src/machine/machine.c | 14 +- src/machine/machinectl.c | 150 +- src/mount/mount-tool.c | 128 +- src/network/generator/network-generator.c | 10 +- src/network/meson.build | 38 +- src/network/netdev/bond.c | 2 +- src/network/netdev/bridge.c | 2 +- src/network/netdev/dummy.c | 2 +- src/network/netdev/fou-tunnel.c | 2 +- src/network/netdev/geneve.c | 2 +- src/network/netdev/ifb.c | 11 + src/network/netdev/ifb.h | 13 + src/network/netdev/ipvlan.c | 4 +- src/network/netdev/l2tp-tunnel.c | 2 +- src/network/netdev/macsec.c | 4 +- src/network/netdev/macvlan.c | 4 +- src/network/netdev/netdev.c | 7 +- src/network/netdev/netdev.h | 30 + src/network/netdev/netdevsim.c | 2 +- src/network/netdev/nlmon.c | 2 +- src/network/netdev/tunnel.c | 20 +- src/network/netdev/tuntap.c | 4 +- src/network/netdev/vcan.c | 2 +- src/network/netdev/veth.c | 13 +- src/network/netdev/vlan.c | 4 +- src/network/netdev/vrf.c | 2 +- src/network/netdev/vxcan.c | 6 +- src/network/netdev/vxlan.c | 2 +- src/network/netdev/wireguard.c | 4 +- src/network/netdev/xfrm.c | 2 +- src/network/networkctl.c | 460 ++- src/network/networkd-address-label.c | 12 +- src/network/networkd-address.c | 160 +- src/network/networkd-address.h | 19 +- src/network/networkd-brvlan.c | 6 +- src/network/networkd-can.c | 8 +- src/network/networkd-conf.c | 27 - src/network/networkd-conf.h | 1 - src/network/networkd-dhcp-common.c | 2 +- src/network/networkd-dhcp-server.c | 8 +- src/network/networkd-dhcp4.c | 254 +- src/network/networkd-dhcp4.h | 1 + src/network/networkd-dhcp6.c | 10 +- src/network/networkd-fdb.c | 12 +- src/network/networkd-ipv4ll.c | 2 +- src/network/networkd-ipv6-proxy-ndp.c | 8 +- src/network/networkd-link-bus.c | 10 +- src/network/networkd-link.c | 306 +- src/network/networkd-link.h | 10 + src/network/networkd-manager-bus.c | 7 +- src/network/networkd-manager.c | 61 +- src/network/networkd-ndisc.c | 352 +- src/network/networkd-ndisc.h | 21 + src/network/networkd-neighbor.c | 22 +- src/network/networkd-network-gperf.gperf | 560 +-- src/network/networkd-network.c | 63 +- src/network/networkd-network.h | 18 +- src/network/networkd-nexthop.c | 2 +- src/network/networkd-radv.c | 50 +- src/network/networkd-route.c | 223 +- src/network/networkd-route.h | 14 + src/network/networkd-routing-policy-rule.c | 222 +- src/network/networkd-routing-policy-rule.h | 5 + src/network/networkd-util.c | 8 + src/network/networkd-util.h | 3 + src/network/networkd.c | 37 +- src/network/tc/codel.c | 249 ++ src/network/tc/codel.h | 24 + src/network/tc/fq-codel.c | 346 ++ src/network/tc/fq-codel.h | 28 + src/network/tc/fq.c | 410 ++ src/network/tc/fq.h | 29 + src/network/tc/netem.c | 134 +- src/network/tc/netem.h | 18 +- src/network/tc/qdisc.c | 259 +- src/network/tc/qdisc.h | 67 +- src/network/tc/sfq.c | 89 + src/network/tc/sfq.h | 18 + src/network/tc/tbf.c | 284 ++ src/network/tc/tbf.h | 25 + src/network/tc/tc-util.c | 31 + src/network/tc/tc-util.h | 4 + src/network/tc/teql.c | 90 + src/network/tc/teql.h | 16 + src/network/test-network.c | 15 +- src/network/wait-online/link.c | 13 +- src/network/wait-online/link.h | 2 +- src/network/wait-online/manager.c | 34 +- src/network/wait-online/manager.h | 4 +- src/network/wait-online/wait-online.c | 46 +- src/nspawn/nspawn-mount.c | 152 +- src/nspawn/nspawn-mount.h | 7 +- src/nspawn/nspawn-network.c | 190 +- src/nspawn/nspawn-network.h | 4 +- src/nspawn/nspawn-oci.c | 19 +- src/nspawn/nspawn.c | 146 +- src/nss-systemd/nss-systemd.c | 1014 ++--- src/nss-systemd/nss-systemd.sym | 1 + src/nss-systemd/userdb-glue.c | 344 ++ src/nss-systemd/userdb-glue.h | 20 + src/partition/growfs.c | 154 +- src/partition/makefs.c | 17 +- src/partition/meson.build | 5 + src/partition/repart.c | 3029 ++++++++++++++ src/portable/portable.c | 6 +- src/portable/portablectl.c | 303 +- src/random-seed/random-seed.c | 1 + src/resolve/meson.build | 8 + src/resolve/resolvectl.c | 305 +- src/resolve/resolved-bus.c | 1 + src/resolve/resolved-conf.c | 6 +- src/resolve/resolved-dns-scope.c | 2 +- src/resolve/resolved-dns-server.c | 12 +- src/resolve/resolved-dns-server.h | 5 +- src/resolve/resolved-dnstls-gnutls.c | 6 + src/resolve/resolved-dnstls-openssl.c | 38 +- src/resolve/resolved-etc-hosts.c | 1 + src/resolve/resolved-link-bus.c | 9 +- src/resolve/resolved-link.c | 2 +- src/resolve/resolved-manager.c | 5 +- src/resolve/resolved-mdns.c | 2 +- src/resolve/resolved-util.c | 36 + src/resolve/resolved-util.h | 6 + src/resolve/resolved.c | 26 +- src/resolve/test-resolved-util.c | 32 + src/run-generator/run-generator.c | 3 +- src/shared/ask-password-api.c | 54 +- src/shared/bootspec.c | 15 +- src/shared/bootspec.h | 8 +- src/shared/bus-polkit.c | 1 - src/shared/bus-unit-util.c | 4 +- src/shared/bus-util.c | 4 +- src/shared/bus-wait-for-jobs.h | 1 + src/{core => shared}/chown-recursive.c | 37 + src/{core => shared}/chown-recursive.h | 2 + src/shared/conf-parser.c | 94 +- src/shared/conf-parser.h | 11 +- src/shared/dev-setup.c | 18 +- src/shared/dissect-image.c | 161 +- src/shared/dissect-image.h | 4 + src/shared/dropin.c | 10 +- src/shared/efi-loader.c | 11 +- src/shared/ethtool-util.c | 162 +- src/shared/ethtool-util.h | 24 +- src/shared/format-table.c | 381 +- src/shared/format-table.h | 8 + src/shared/generator.c | 97 + src/shared/generator.h | 15 + src/shared/gpt.c | 70 + src/shared/gpt.h | 20 + src/shared/group-record-nss.c | 203 + src/shared/group-record-nss.h | 15 + src/shared/group-record-show.c | 76 + src/shared/group-record-show.h | 6 + src/shared/group-record.c | 346 ++ src/shared/group-record.h | 44 + src/shared/id128-print.c | 42 +- src/shared/id128-print.h | 1 + src/shared/import-util.c | 14 + src/shared/import-util.h | 2 + src/shared/install.c | 116 +- src/shared/install.h | 2 + src/shared/journal-importer.h | 3 +- src/shared/journal-util.c | 6 +- src/shared/journal-util.h | 2 +- src/shared/json.c | 898 +++- src/shared/json.h | 76 +- src/shared/libcrypt-util.c | 86 + src/shared/libcrypt-util.h | 22 + src/shared/logs-show.c | 130 +- src/shared/logs-show.h | 1 + src/shared/loop-util.c | 365 +- src/shared/loop-util.h | 9 +- src/shared/machine-image.c | 7 +- src/shared/main-func.h | 4 + src/shared/meson.build | 39 + src/shared/module-util.c | 2 +- src/shared/mount-util.c | 180 +- src/shared/mount-util.h | 3 +- .../netif-naming-scheme.c} | 4 +- .../netif-naming-scheme.h} | 2 + src/shared/nsflags.c | 6 - src/shared/openssl-util.h | 12 + src/shared/output-mode.h | 17 +- src/shared/pam-util.c | 81 + src/shared/pam-util.h | 15 + src/shared/pkcs11-util.c | 912 +++++ src/shared/pkcs11-util.h | 45 + src/shared/resize-fs.c | 123 + src/shared/resize-fs.h | 15 + src/shared/seccomp-util.c | 10 +- src/shared/sleep-config.c | 190 +- src/shared/sleep-config.h | 4 +- src/shared/socket-netlink.c | 363 ++ src/shared/socket-netlink.h | 23 + src/shared/sysctl-util.h | 2 +- src/shared/unit-file.c | 35 + src/shared/unit-file.h | 1 + src/shared/user-record-nss.c | 260 ++ src/shared/user-record-nss.h | 15 + src/shared/user-record-show.c | 466 +++ src/shared/user-record-show.h | 8 + src/shared/user-record.c | 1883 +++++++++ src/shared/user-record.h | 375 ++ src/shared/userdb.c | 1335 ++++++ src/shared/userdb.h | 41 + src/shared/varlink.c | 49 +- src/shared/varlink.h | 6 + src/shutdown/umount.c | 114 +- src/sleep/sleep.c | 62 +- src/socket-proxy/socket-proxyd.c | 13 +- src/sulogin-shell/sulogin-shell.c | 6 +- src/sysctl/sysctl.c | 231 +- src/systemctl/systemctl.c | 896 ++-- src/systemd/_sd-common.h | 12 + src/systemd/sd-bus-vtable.h | 1 + src/systemd/sd-bus.h | 10 + src/systemd/sd-dhcp-client.h | 1 + src/systemd/sd-event.h | 12 + src/systemd/sd-journal.h | 17 +- src/systemd/sd-netlink.h | 2 + src/sysusers/sysusers.c | 95 +- src/test/generate-sym-test.py | 3 + src/test/meson.build | 4 + src/test/test-ask-password-api.c | 22 +- src/test/test-btrfs.c | 2 +- src/test/test-capability.c | 16 +- src/test/test-conf-parser.c | 50 +- src/test/test-dev-setup.c | 3 +- src/test/test-dissect-image.c | 5 +- src/test/test-escape.c | 16 + src/test/test-execute.c | 2 + src/test/test-format-table.c | 227 ++ src/test/test-fs-util.c | 59 +- src/test/test-id128.c | 2 +- src/test/test-install-root.c | 164 + src/test/test-json.c | 104 +- src/test/test-locale-util.c | 1 - src/test/test-namespace.c | 1 + src/test/test-ns.c | 3 +- src/test/test-process-util.c | 92 +- src/test/test-seccomp.c | 2 +- src/test/test-sizeof.c | 3 + src/test/test-socket-netlink.c | 227 ++ src/test/test-socket-util.c | 221 +- src/test/test-string-util.c | 173 + src/test/test-strv.c | 36 +- src/test/test-unit-name.c | 4 + src/test/test-user-util.c | 44 +- src/test/test-util.c | 12 + src/timedate/timedatectl.c | 273 +- src/timesync/timesyncd-manager.c | 2 +- src/tmpfiles/tmpfiles.c | 2 +- .../tty-ask-password-agent.c | 14 +- src/udev/ata_id/ata_id.c | 2 +- src/udev/meson.build | 2 - src/udev/net/link-config-gperf.gperf | 77 +- src/udev/net/link-config.c | 111 +- src/udev/net/link-config.h | 9 +- src/udev/udev-builtin-hwdb.c | 4 +- src/udev/udev-builtin-input_id.c | 28 +- src/udev/udev-builtin-net_id.c | 46 +- src/udev/udev-event.c | 39 +- src/udev/udevadm-info.c | 8 +- src/udev/udevd.c | 6 +- src/userdb/meson.build | 15 + src/userdb/userdbctl.c | 792 ++++ src/userdb/userdbd-manager.c | 301 ++ src/userdb/userdbd-manager.h | 34 + src/userdb/userdbd.c | 56 + src/userdb/userwork.c | 778 ++++ src/veritysetup/veritysetup-generator.c | 2 +- src/version/version.h.in | 7 + sysctl.d/50-default.conf | 12 +- test/README.testsuite | 2 +- test/TEST-01-BASIC/test.sh | 2 +- test/TEST-02-CRYPTSETUP/test.sh | 2 +- test/TEST-03-JOBS/test-jobs.sh | 3 +- test/TEST-03-JOBS/test.sh | 2 +- test/TEST-04-JOURNAL/test-journal.sh | 2 +- test/TEST-04-JOURNAL/test.sh | 2 +- test/TEST-05-RLIMITS/test-rlimits.sh | 2 +- test/TEST-05-RLIMITS/test.sh | 2 +- test/TEST-06-SELINUX/test-selinux-checks.sh | 2 +- test/TEST-06-SELINUX/test.sh | 2 +- test/TEST-07-ISSUE-1981/test-segfault.sh | 2 +- test/TEST-07-ISSUE-1981/test.sh | 2 +- test/TEST-08-ISSUE-2730/test.sh | 4 +- test/TEST-09-ISSUE-2691/test.sh | 4 +- test/TEST-10-ISSUE-2467/test.sh | 2 +- test/TEST-11-ISSUE-3166/test.sh | 5 +- test/TEST-12-ISSUE-3171/test.sh | 4 +- .../create-busybox-container | 2 +- test/TEST-13-NSPAWN-SMOKE/test.sh | 7 +- test/TEST-14-MACHINE-ID/test.sh | 4 +- test/TEST-15-DROPIN/test-dropin.sh | 25 + test/TEST-15-DROPIN/test.sh | 2 +- test/TEST-16-EXTEND-TIMEOUT/assess.sh | 2 +- .../extend_timeout_test_service.sh | 2 +- test/TEST-16-EXTEND-TIMEOUT/test.sh | 2 +- test/TEST-17-UDEV-WANTS/test.sh | 2 +- test/TEST-17-UDEV-WANTS/testsuite.sh | 2 +- test/TEST-18-FAILUREACTION/test.sh | 2 +- test/TEST-18-FAILUREACTION/testsuite.sh | 2 +- test/TEST-19-DELEGATE/test.sh | 2 +- test/TEST-19-DELEGATE/testsuite.sh | 2 +- test/TEST-20-MAINPIDGAMES/test.sh | 2 +- test/TEST-20-MAINPIDGAMES/testsuite.sh | 8 +- test/TEST-21-SYSUSERS/test-13.expected-group | 5 + test/TEST-21-SYSUSERS/test-13.expected-passwd | 5 + test/TEST-21-SYSUSERS/test-13.input | 13 + test/TEST-21-SYSUSERS/test-14.expected-group | 1 + test/TEST-21-SYSUSERS/test-14.expected-passwd | 1 + test/TEST-21-SYSUSERS/test-14.initial-group | 1 + test/TEST-21-SYSUSERS/test-14.input | 4 + test/TEST-21-SYSUSERS/test.sh | 4 +- test/TEST-21-SYSUSERS/unhappy-3.expected-err | 1 + test/TEST-21-SYSUSERS/unhappy-3.input | 4 + test/TEST-22-TMPFILES/run-tmpfiles-tests.sh | 2 +- test/TEST-22-TMPFILES/test-09.sh | 2 +- test/TEST-22-TMPFILES/test.sh | 2 +- test/TEST-23-TYPE-EXEC/test.sh | 2 +- test/TEST-23-TYPE-EXEC/testsuite.sh | 2 +- test/TEST-24-UNIT-TESTS/test.sh | 2 +- test/TEST-24-UNIT-TESTS/testsuite.sh | 2 +- test/TEST-25-IMPORT/test.sh | 2 +- test/TEST-25-IMPORT/testsuite.sh | 2 +- test/TEST-26-SETENV/test.sh | 2 +- test/TEST-26-SETENV/testsuite.sh | 2 +- test/TEST-27-STDOUTFILE/test.sh | 2 +- test/TEST-27-STDOUTFILE/testsuite.sh | 2 +- test/TEST-28-PERCENTJ-WANTEDBY/test.sh | 2 +- test/TEST-29-UDEV-ID_RENAMING/test.sh | 2 +- test/TEST-29-UDEV-ID_RENAMING/testsuite.sh | 2 +- test/TEST-30-ONCLOCKCHANGE/test.sh | 2 +- test/TEST-30-ONCLOCKCHANGE/testsuite.sh | 2 +- test/TEST-31-DEVICE-ENUMERATION/test.sh | 2 +- test/TEST-31-DEVICE-ENUMERATION/testsuite.sh | 2 +- test/TEST-32-OOMPOLICY/test.sh | 2 +- test/TEST-32-OOMPOLICY/testsuite.sh | 2 +- test/TEST-33-CLEAN-UNIT/test.sh | 2 +- test/TEST-33-CLEAN-UNIT/testsuite.sh | 2 +- test/TEST-34-DYNAMICUSERMIGRATE/test.sh | 2 +- test/TEST-34-DYNAMICUSERMIGRATE/testsuite.sh | 2 +- .../90-enp3s0.network | 17 + .../test-03-issue-14319.input | 1 + test/TEST-35-NETWORK-GENERATOR/test.sh | 2 +- test/TEST-36-NUMAPOLICY/test.sh | 2 +- test/TEST-36-NUMAPOLICY/testsuite.sh | 2 +- test/TEST-37-RUNTIMEDIRECTORYPRESERVE/test.sh | 2 +- .../testsuite.sh | 2 +- test/TEST-39-EXECRELOAD/test.sh | 2 +- test/TEST-39-EXECRELOAD/testsuite.sh | 2 +- test/TEST-40-EXEC-COMMAND-EX/Makefile | 10 +- test/TEST-40-EXEC-COMMAND-EX/test.sh | 2 +- test/TEST-40-EXEC-COMMAND-EX/testsuite.sh | 2 +- test/TEST-41-ONESHOT-RESTART/Makefile | 10 +- test/TEST-41-ONESHOT-RESTART/test.sh | 2 +- test/TEST-41-ONESHOT-RESTART/testsuite.sh | 2 +- test/TEST-42-EXECSTOPPOST/Makefile | 10 +- test/TEST-42-EXECSTOPPOST/test.sh | 2 +- test/TEST-42-EXECSTOPPOST/testsuite.sh | 8 +- test/TEST-43-PRIVATEUSER-UNPRIV/Makefile | 1 + test/TEST-43-PRIVATEUSER-UNPRIV/test.sh | 49 + test/TEST-43-PRIVATEUSER-UNPRIV/testsuite.sh | 68 + test/TEST-44-LOG-NAMESPACE/Makefile | 1 + test/TEST-44-LOG-NAMESPACE/test.sh | 39 + test/TEST-44-LOG-NAMESPACE/testsuite.sh | 19 + test/TEST-45-REPART/Makefile | 1 + test/TEST-45-REPART/test.sh | 37 + test/TEST-45-REPART/testsuite.sh | 120 + test/TEST-46-HOMED/Makefile | 1 + test/TEST-46-HOMED/test.sh | 42 + test/TEST-46-HOMED/testsuite.sh | 74 + test/fuzz/fuzz-link-parser/directives.link | 5 + .../fuzz-network-parser/directives.network | 66 + test/fuzz/fuzz-network-parser/oss-fuzz-20548 | Bin 0 -> 26 bytes test/fuzz/fuzz-unit-file/directives.service | 1 + test/meson.build | 2 + test/mkosi.default.networkd-test | 1 - test/mocks/fsck | 2 +- test/networkd-test.py | 4 +- test/run-integration-tests.sh | 3 +- test/test-efi-create-disk.sh | 3 +- test/test-exec-deserialization.py | 14 +- test/test-execute/exec-basic.service | 1 - ...exec-privatedevices-yes-with-group.service | 16 + ...exec-privatetmp-disabled-by-prefix.service | 8 + test/test-functions | 74 +- test/test-network/conf/12-dummy-mtu.link | 5 + test/test-network/conf/12-dummy-mtu.netdev | 4 + test/test-network/conf/12-dummy.link | 5 + test/test-network/conf/12-dummy.network | 7 + .../12-dummy.network.d/ipv6-mtu-1400.conf | 2 + .../12-dummy.network.d/ipv6-mtu-1550.conf | 2 + .../conf/12-dummy.network.d/mtu.conf | 2 + .../conf/25-address-dad-veth-peer.network | 9 + .../conf/25-address-dad-veth99.network | 8 + .../conf/25-fibrule-uidrange.network | 9 + test/test-network/conf/25-ifb.netdev | 3 + .../conf/25-qdisc-clsact-root-compat.network | 12 + .../conf/25-qdisc-fq-codel.network | 27 + ... => 25-qdisc-ingress-netem-compat.network} | 10 +- .../conf/25-qdisc-ingress-root.network | 12 + .../conf/25-qdisc-netem-and-fqcodel.network | 25 + .../conf/25-qdisc-tbf-and-sfq.network | 19 + test/test-network/conf/25-qdisc-teql.network | 11 + .../test-network/conf/25-route-static.network | 19 + test/test-network/conf/25-route-vrf.network | 7 + .../conf/dhcp-client-decline.network | 9 + .../conf/dhcp-client-gateway-ipv4.network | 10 + .../conf/dhcp-client-gateway-ipv6.network | 9 + .../dhcp-client-ipv4-use-routes-no.network | 9 + .../conf/dhcp-server-decline.network | 14 + ...pv6-prefix-veth-token-prefixstable.network | 6 + ...-prefix-veth-token-static-explicit.network | 6 + ...-prefix-veth-token-static-multiple.network | 7 + .../ipv6-prefix-veth-token-static.network | 6 + test/test-network/conf/ipv6-prefix.network | 4 + .../netdev-link-local-addressing-yes.network | 2 + test/test-network/systemd-networkd-tests.py | 645 ++- tmpfiles.d/systemd.conf.m4 | 31 +- tools/check-directives.sh | 2 +- tools/chromiumos/gen_autosuspend_rules.py | 21 +- tools/coverity.sh | 2 +- tools/meson-vcs-tag.sh | 2 +- tools/oss-fuzz.sh | 2 +- travis-ci/managers/debian.sh | 10 +- travis-ci/managers/fedora.sh | 12 +- travis-ci/managers/fuzzbuzz.sh | 4 +- travis-ci/managers/fuzzit.sh | 2 + units/blockdev@.target | 13 + ...anup.service.in => initrd-cleanup.service} | 2 +- units/initrd-fs.target | 2 - ...tc.service.in => initrd-parse-etc.service} | 6 +- units/initrd-root-device.target | 2 - units/initrd-root-fs.target | 2 - ....service.in => initrd-switch-root.service} | 2 +- ...e.in => initrd-udevadm-cleanup-db.service} | 2 +- units/initrd.target | 2 - units/local-fs.target | 2 - units/meson.build | 77 +- units/modprobe@.service | 20 + units/sys-kernel-tracing.mount | 23 + "units/system-systemd\\x2dcryptsetup.slice" | 13 + ...n => systemd-ask-password-console.service} | 2 +- ...e.in => systemd-ask-password-wall.service} | 4 +- ...e.in => systemd-boot-system-token.service} | 2 +- ...t.service.in => systemd-firstboot.service} | 2 +- ...d-halt.service.in => systemd-halt.service} | 2 +- units/systemd-homed.service.in | 36 + units/systemd-hwdb-update.service.in | 2 +- ...=> systemd-journal-catalog-update.service} | 2 +- ...rvice.in => systemd-journal-flush.service} | 4 +- units/systemd-journald-varlink@.socket | 18 + units/systemd-journald.service.in | 4 +- units/systemd-journald@.service.in | 44 + units/systemd-journald@.socket | 24 + ...kexec.service.in => systemd-kexec.service} | 2 +- units/systemd-logind.service.in | 5 +- ...e.in => systemd-machine-id-commit.service} | 2 +- units/systemd-machined.service.in | 1 - units/systemd-network-generator.service.in | 2 + units/systemd-networkd.service.in | 2 +- units/systemd-networkd.socket | 2 +- units/systemd-nspawn@.service.in | 8 +- units/systemd-pstore.service.in | 1 + units/systemd-repart.service.in | 25 + ...rs.service.in => systemd-sysusers.service} | 2 +- ...vice.in => systemd-tmpfiles-clean.service} | 2 +- ....in => systemd-tmpfiles-setup-dev.service} | 2 +- ...vice.in => systemd-tmpfiles-setup.service} | 2 +- ...service.in => systemd-udev-settle.service} | 2 +- ...ervice.in => systemd-udev-trigger.service} | 4 +- units/systemd-udevd.service.in | 2 +- units/systemd-userdbd.service.in | 41 + units/systemd-userdbd.socket | 19 + units/systemd-vconsole-setup.service.in | 1 + units/user/meson.build | 18 +- ...vice.in => systemd-tmpfiles-clean.service} | 2 +- ...vice.in => systemd-tmpfiles-setup.service} | 2 +- units/user@.service.in | 2 +- 944 files changed, 67075 insertions(+), 10427 deletions(-) create mode 100644 docs/.gitignore create mode 100644 docs/CONTAINER_INTERFACE.md create mode 100644 docs/DISCOVERABLE_PARTITIONS.md create mode 100644 docs/GROUP_RECORD.md create mode 100644 docs/HOME_DIRECTORY.md create mode 100644 docs/INITRD_INTERFACE.md create mode 100644 docs/PORTABILITY_AND_STABILITY.md create mode 100644 docs/ROOT_STORAGE_DAEMONS.md create mode 100644 docs/USER_GROUP_API.md create mode 100644 docs/USER_RECORD.md create mode 100644 docs/_data/extra_pages.json create mode 100644 docs/_includes/footer.html create mode 100644 docs/_includes/head.html create mode 100644 docs/_includes/header.html create mode 100644 docs/_layouts/default.html create mode 100644 docs/assets/page-logo.svg create mode 100644 docs/favicon.png create mode 100644 docs/favicon.svg create mode 100644 docs/fonts/heebo-bold.woff create mode 100644 docs/fonts/heebo-regular.woff create mode 100644 docs/style.css create mode 100644 man/homectl.xml create mode 100644 man/pam_systemd_home.xml create mode 100644 man/repart.d.xml create mode 100644 man/sd_bus_enqueue_for_read.xml create mode 100644 man/sd_bus_message_dump.xml create mode 100644 man/sd_bus_message_sensitive.xml create mode 100644 man/supported-controllers.xml create mode 100644 man/systemd-homed.service.xml create mode 100644 man/systemd-network-generator.service.xml rename man/{systemd-pstore.xml => systemd-pstore.service.xml} (89%) create mode 100644 man/systemd-repart.xml create mode 100644 man/systemd-userdbd.service.xml create mode 100644 man/userdbctl.xml create mode 100644 man/yubikey-crypttab.sh create mode 100644 src/basic/missing_xfs.h create mode 100644 src/basic/quota-util.c create mode 100644 src/basic/quota-util.h create mode 100644 src/core/core-varlink.c create mode 100644 src/core/core-varlink.h create mode 100644 src/cryptsetup/cryptsetup-pkcs11.c create mode 100644 src/cryptsetup/cryptsetup-pkcs11.h create mode 100644 src/home/home-util.c create mode 100644 src/home/home-util.h create mode 100644 src/home/homectl.c create mode 100644 src/home/homed-bus.c create mode 100644 src/home/homed-bus.h create mode 100644 src/home/homed-home-bus.c create mode 100644 src/home/homed-home-bus.h create mode 100644 src/home/homed-home.c create mode 100644 src/home/homed-home.h create mode 100644 src/home/homed-manager-bus.c create mode 100644 src/home/homed-manager-bus.h create mode 100644 src/home/homed-manager.c create mode 100644 src/home/homed-manager.h create mode 100644 src/home/homed-operation.c create mode 100644 src/home/homed-operation.h create mode 100644 src/home/homed-varlink.c create mode 100644 src/home/homed-varlink.h create mode 100644 src/home/homed.c create mode 100644 src/home/homework-cifs.c create mode 100644 src/home/homework-cifs.h create mode 100644 src/home/homework-directory.c create mode 100644 src/home/homework-directory.h create mode 100644 src/home/homework-fscrypt.c create mode 100644 src/home/homework-fscrypt.h create mode 100644 src/home/homework-luks.c create mode 100644 src/home/homework-luks.h create mode 100644 src/home/homework-mount.c create mode 100644 src/home/homework-mount.h create mode 100644 src/home/homework-pkcs11.c create mode 100644 src/home/homework-pkcs11.h create mode 100644 src/home/homework-quota.c create mode 100644 src/home/homework-quota.h create mode 100644 src/home/homework.c create mode 100644 src/home/homework.h create mode 100644 src/home/meson.build create mode 100644 src/home/org.freedesktop.home1.conf create mode 100644 src/home/org.freedesktop.home1.policy create mode 100644 src/home/org.freedesktop.home1.service create mode 100644 src/home/pam_systemd_home.c create mode 100644 src/home/pam_systemd_home.sym create mode 100644 src/home/pwquality-util.c create mode 100644 src/home/pwquality-util.h create mode 100644 src/home/user-record-sign.c create mode 100644 src/home/user-record-sign.h create mode 100644 src/home/user-record-util.c create mode 100644 src/home/user-record-util.h create mode 100644 src/network/netdev/ifb.c create mode 100644 src/network/netdev/ifb.h create mode 100644 src/network/tc/codel.c create mode 100644 src/network/tc/codel.h create mode 100644 src/network/tc/fq-codel.c create mode 100644 src/network/tc/fq-codel.h create mode 100644 src/network/tc/fq.c create mode 100644 src/network/tc/fq.h create mode 100644 src/network/tc/sfq.c create mode 100644 src/network/tc/sfq.h create mode 100644 src/network/tc/tbf.c create mode 100644 src/network/tc/tbf.h create mode 100644 src/network/tc/teql.c create mode 100644 src/network/tc/teql.h create mode 100644 src/nss-systemd/userdb-glue.c create mode 100644 src/nss-systemd/userdb-glue.h create mode 100644 src/partition/meson.build create mode 100644 src/partition/repart.c create mode 100644 src/resolve/resolved-util.c create mode 100644 src/resolve/resolved-util.h create mode 100644 src/resolve/test-resolved-util.c rename src/{core => shared}/chown-recursive.c (76%) rename src/{core => shared}/chown-recursive.h (69%) create mode 100644 src/shared/gpt.c create mode 100644 src/shared/group-record-nss.c create mode 100644 src/shared/group-record-nss.h create mode 100644 src/shared/group-record-show.c create mode 100644 src/shared/group-record-show.h create mode 100644 src/shared/group-record.c create mode 100644 src/shared/group-record.h create mode 100644 src/shared/libcrypt-util.c create mode 100644 src/shared/libcrypt-util.h rename src/{udev/net/naming-scheme.c => shared/netif-naming-scheme.c} (96%) rename src/{udev/net/naming-scheme.h => shared/netif-naming-scheme.h} (94%) create mode 100644 src/shared/openssl-util.h create mode 100644 src/shared/pam-util.c create mode 100644 src/shared/pam-util.h create mode 100644 src/shared/pkcs11-util.c create mode 100644 src/shared/pkcs11-util.h create mode 100644 src/shared/resize-fs.c create mode 100644 src/shared/resize-fs.h create mode 100644 src/shared/socket-netlink.c create mode 100644 src/shared/socket-netlink.h create mode 100644 src/shared/user-record-nss.c create mode 100644 src/shared/user-record-nss.h create mode 100644 src/shared/user-record-show.c create mode 100644 src/shared/user-record-show.h create mode 100644 src/shared/user-record.c create mode 100644 src/shared/user-record.h create mode 100644 src/shared/userdb.c create mode 100644 src/shared/userdb.h create mode 100644 src/test/test-socket-netlink.c create mode 100644 src/userdb/meson.build create mode 100644 src/userdb/userdbctl.c create mode 100644 src/userdb/userdbd-manager.c create mode 100644 src/userdb/userdbd-manager.h create mode 100644 src/userdb/userdbd.c create mode 100644 src/userdb/userwork.c create mode 100644 test/TEST-21-SYSUSERS/test-13.expected-group create mode 100644 test/TEST-21-SYSUSERS/test-13.expected-passwd create mode 100644 test/TEST-21-SYSUSERS/test-13.input create mode 100644 test/TEST-21-SYSUSERS/test-14.expected-group create mode 100644 test/TEST-21-SYSUSERS/test-14.expected-passwd create mode 100644 test/TEST-21-SYSUSERS/test-14.initial-group create mode 100644 test/TEST-21-SYSUSERS/test-14.input create mode 100644 test/TEST-21-SYSUSERS/unhappy-3.expected-err create mode 100644 test/TEST-21-SYSUSERS/unhappy-3.input create mode 100644 test/TEST-35-NETWORK-GENERATOR/test-03-issue-14319.expected/90-enp3s0.network create mode 100644 test/TEST-35-NETWORK-GENERATOR/test-03-issue-14319.input mode change 100644 => 120000 test/TEST-40-EXEC-COMMAND-EX/Makefile mode change 100644 => 120000 test/TEST-41-ONESHOT-RESTART/Makefile mode change 100644 => 120000 test/TEST-42-EXECSTOPPOST/Makefile create mode 120000 test/TEST-43-PRIVATEUSER-UNPRIV/Makefile create mode 100755 test/TEST-43-PRIVATEUSER-UNPRIV/test.sh create mode 100755 test/TEST-43-PRIVATEUSER-UNPRIV/testsuite.sh create mode 120000 test/TEST-44-LOG-NAMESPACE/Makefile create mode 100755 test/TEST-44-LOG-NAMESPACE/test.sh create mode 100755 test/TEST-44-LOG-NAMESPACE/testsuite.sh create mode 120000 test/TEST-45-REPART/Makefile create mode 100755 test/TEST-45-REPART/test.sh create mode 100755 test/TEST-45-REPART/testsuite.sh create mode 120000 test/TEST-46-HOMED/Makefile create mode 100755 test/TEST-46-HOMED/test.sh create mode 100755 test/TEST-46-HOMED/testsuite.sh create mode 100644 test/fuzz/fuzz-network-parser/oss-fuzz-20548 create mode 100644 test/test-execute/exec-privatedevices-yes-with-group.service create mode 100644 test/test-execute/exec-privatetmp-disabled-by-prefix.service create mode 100644 test/test-network/conf/12-dummy-mtu.link create mode 100644 test/test-network/conf/12-dummy-mtu.netdev create mode 100644 test/test-network/conf/12-dummy.link create mode 100644 test/test-network/conf/12-dummy.network create mode 100644 test/test-network/conf/12-dummy.network.d/ipv6-mtu-1400.conf create mode 100644 test/test-network/conf/12-dummy.network.d/ipv6-mtu-1550.conf create mode 100644 test/test-network/conf/12-dummy.network.d/mtu.conf create mode 100644 test/test-network/conf/25-address-dad-veth-peer.network create mode 100644 test/test-network/conf/25-address-dad-veth99.network create mode 100644 test/test-network/conf/25-fibrule-uidrange.network create mode 100644 test/test-network/conf/25-ifb.netdev create mode 100644 test/test-network/conf/25-qdisc-clsact-root-compat.network create mode 100644 test/test-network/conf/25-qdisc-fq-codel.network rename test/test-network/conf/{25-qdisc.network => 25-qdisc-ingress-netem-compat.network} (58%) create mode 100644 test/test-network/conf/25-qdisc-ingress-root.network create mode 100644 test/test-network/conf/25-qdisc-netem-and-fqcodel.network create mode 100644 test/test-network/conf/25-qdisc-tbf-and-sfq.network create mode 100644 test/test-network/conf/25-qdisc-teql.network create mode 100644 test/test-network/conf/25-route-vrf.network create mode 100644 test/test-network/conf/dhcp-client-decline.network create mode 100644 test/test-network/conf/dhcp-client-gateway-ipv4.network create mode 100644 test/test-network/conf/dhcp-client-gateway-ipv6.network create mode 100644 test/test-network/conf/dhcp-client-ipv4-use-routes-no.network create mode 100644 test/test-network/conf/dhcp-server-decline.network create mode 100644 test/test-network/conf/ipv6-prefix-veth-token-prefixstable.network create mode 100644 test/test-network/conf/ipv6-prefix-veth-token-static-explicit.network create mode 100644 test/test-network/conf/ipv6-prefix-veth-token-static-multiple.network create mode 100644 test/test-network/conf/ipv6-prefix-veth-token-static.network create mode 100644 units/blockdev@.target rename units/{initrd-cleanup.service.in => initrd-cleanup.service} (88%) rename units/{initrd-parse-etc.service.in => initrd-parse-etc.service} (77%) rename units/{initrd-switch-root.service.in => initrd-switch-root.service} (89%) rename units/{initrd-udevadm-cleanup-db.service.in => initrd-udevadm-cleanup-db.service} (93%) create mode 100644 units/modprobe@.service create mode 100644 units/sys-kernel-tracing.mount create mode 100644 "units/system-systemd\\x2dcryptsetup.slice" rename units/{systemd-ask-password-console.service.in => systemd-ask-password-console.service} (90%) rename units/{systemd-ask-password-wall.service.in => systemd-ask-password-wall.service} (68%) rename units/{systemd-boot-system-token.service.in => systemd-boot-system-token.service} (96%) rename units/{systemd-firstboot.service.in => systemd-firstboot.service} (87%) rename units/{systemd-halt.service.in => systemd-halt.service} (93%) create mode 100644 units/systemd-homed.service.in rename units/{systemd-journal-catalog-update.service.in => systemd-journal-catalog-update.service} (93%) rename units/{systemd-journal-flush.service.in => systemd-journal-flush.service} (87%) create mode 100644 units/systemd-journald-varlink@.socket create mode 100644 units/systemd-journald@.service.in create mode 100644 units/systemd-journald@.socket rename units/{systemd-kexec.service.in => systemd-kexec.service} (93%) rename units/{systemd-machine-id-commit.service.in => systemd-machine-id-commit.service} (92%) create mode 100644 units/systemd-repart.service.in rename units/{systemd-sysusers.service.in => systemd-sysusers.service} (94%) rename units/{systemd-tmpfiles-clean.service.in => systemd-tmpfiles-clean.service} (92%) rename units/{systemd-tmpfiles-setup-dev.service.in => systemd-tmpfiles-setup-dev.service} (90%) rename units/{systemd-tmpfiles-setup.service.in => systemd-tmpfiles-setup.service} (89%) rename units/{systemd-udev-settle.service.in => systemd-udev-settle.service} (95%) rename units/{systemd-udev-trigger.service.in => systemd-udev-trigger.service} (82%) create mode 100644 units/systemd-userdbd.service.in create mode 100644 units/systemd-userdbd.socket rename units/user/{systemd-tmpfiles-clean.service.in => systemd-tmpfiles-clean.service} (91%) rename units/user/{systemd-tmpfiles-setup.service.in => systemd-tmpfiles-setup.service} (90%) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index ee3b80224..b720b58a2 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1 @@ -custom: ['https://spi-inc.org/projects/systemd/', 'https://www.paypal.com/donate/?token=fBGzXDOyIGobZH3oEhYQlYlA61OMRXVnF9XXQqNNehRs-nliAU5XxozIh9z-hlmE-xXC-m'] +custom: ['https://spi-inc.org/projects/systemd/'] diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md index 6a0b5527d..63ccea9a6 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -8,7 +8,7 @@ about: A report of an error in a recent systemd version > ... - + **Used distribution** > … diff --git a/.lgtm.yml b/.lgtm.yml index 5948d8c2b..79512df98 100644 --- a/.lgtm.yml +++ b/.lgtm.yml @@ -1,13 +1,14 @@ +--- +# vi: ts=2 sw=2 et: + extraction: cpp: prepare: packages: - - python3-pip - - python3-setuptools - - python3-wheel - after_prepare: - - pip3 install meson - - export PATH="$HOME/.local/bin/:$PATH" + - libpwquality-dev + - libfdisk-dev + - libp11-kit-dev + - libssl-dev python: python_setup: version: 3 diff --git a/.mailmap b/.mailmap index 2bfc64695..3f3af64d7 100644 --- a/.mailmap +++ b/.mailmap @@ -30,6 +30,7 @@ Daniel Machon Daniel Rusek Daniel Stekloff Daniel Șerbănescu +Dann Frazier Dave Reisner David Zeuthen David Zeuthen @@ -164,6 +165,7 @@ Stefan Schweter Stuart McLaren Susant Sahani <145210+ssahani@users.noreply.github.com> Susant Sahani +Sylvain Plantefeve Sébastien Bacher Tanu Kaskinen Ted Ts'o diff --git a/.mkosi/mkosi.fedora b/.mkosi/mkosi.fedora index 911908cb7..01bfd2338 100644 --- a/.mkosi/mkosi.fedora +++ b/.mkosi/mkosi.fedora @@ -8,9 +8,8 @@ Distribution=fedora Release=31 [Output] -Format=raw_btrfs +Format=gpt_ext4 Bootable=yes -KernelCommandLine=printk.devkmsg=on [Partitions] RootSize=3G @@ -27,6 +26,7 @@ BuildPackages= gcc gettext git + glibc-minimal-langpack gnu-efi gnu-efi-devel gnutls-devel @@ -38,19 +38,22 @@ BuildPackages= libblkid-devel libcap-devel libcurl-devel + libfdisk-devel libgcrypt-devel libidn2-devel libmicrohttpd-devel libmount-devel + libpwquality-devel libseccomp-devel libselinux-devel - libtool libxkbcommon-devel libxslt lz4 lz4-devel m4 meson + openssl-devel + p11-kit-devel pam-devel pcre2-devel pkgconfig @@ -58,10 +61,18 @@ BuildPackages= python3-lxml qrencode-devel tree + valgrind-devel xz-devel Packages= + coreutils + cryptsetup-libs + kmod-libs + e2fsprogs libidn2 + libseccomp + procps-ng + util-linux BuildDirectory=mkosi.builddir Cache=mkosi.cache diff --git a/NEWS b/NEWS index 4fe5799c0..7f241fd64 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,314 @@ systemd System and Service Manager +CHANGES WITH 245: + + * A new tool "systemd-repart" has been added, that operates as an + idempotent declarative repartitioner for GPT partition tables. + Specifically, a set of partitions that must or may exist can be + configured via drop-in files, and during every boot the partition + table on disk is compared with these files, creating missing + partitions or growing existing ones based on configurable relative + and absolute size constraints. The tool is strictly incremental, + i.e. does not delete, shrink or move partitions, but only adds and + grows them. The primary use-case is OS images that ship in minimized + form, that on first boot are grown to the size of the underlying + block device or augmented with additional partitions. For example, + the root partition could be extended to cover the whole disk, or a + swap or /home partitions could be added on first boot. It can also be + used for systems that use an A/B update scheme but ship images with + just the A partition, with B added on first boot. The tool is + primarily intended to be run in the initrd, shortly before + transitioning into the host OS, but can also be run after the + transition took place. It automatically discovers the disk backing + the root file system, and should hence not require any additional + configuration besides the partition definition drop-ins. If no + configuration drop-ins are present, no action is taken. + + * A new component "userdb" has been added, along with a small daemon + "systemd-userdb.service" and a client tool "userdbctl". The framework + allows defining rich user and group records in a JSON format, + extending on the classic "struct passwd" and "struct group" + structures. Various components in systemd have been updated to + process records in this format, including systemd-logind and + pam-systemd. The user records are intended to be extensible, and + allow setting various resource management, security and runtime + parameters that shall be applied to processes and sessions of the + user as they log in. This facility is intended to allow associating + such metadata directly with user/group records so that they can be + produced, extended and consumed in unified form. We hope that + eventually frameworks such as sssd will generate records this way, so + that for the first time resource management and various other + per-user settings can be configured in LDAP directories and then + provided to systemd (specifically to systemd-logind and pam-system) + to apply on login. For further details see: + + https://systemd.io/USER_RECORD + https://systemd.io/GROUP_RECORD + https://systemd.io/USER_GROUP_API + + * A small new service systemd-homed.service has been added, that may be + used to securely manage home directories with built-in encryption. + The complete user record data is unified with the home directory, + thus making home directories naturally migratable. Its primary + back-end is based on LUKS volumes, but fscrypt, plain directories, + and other storage schemes are also supported. This solves a couple of + problems we saw with traditional ways to manage home directories, in + particular when it comes to encryption. For further discussion of + this, see the video of Lennart's talk at AllSystemsGo! 2019: + + https://media.ccc.de/v/ASG2019-164-reinventing-home-directories + + For further details about the format and expectations on home + directories this new daemon makes, see: + + https://systemd.io/HOME_DIRECTORY + + * systemd-journald is now multi-instantiable. In addition to the main + instance systemd-journald.service there's now a template unit + systemd-journald@.service, with each instance defining a new named + log 'namespace' (whose name is specified via the instance part of the + unit name). A new unit file setting LogNamespace= has been added, + taking such a namespace name, that assigns services to the specified + log namespaces. As each log namespace is serviced by its own + independent journal daemon, this functionality may be used to improve + performance and increase isolation of applications, at the price of + losing global message ordering. Each instance of journald has a + separate set of configuration files, with possibly different disk + usage limitations and other settings. + + journalctl now takes a new option --namespace= to show logs from a + specific log namespace. The sd-journal.h API gained + sd_journal_open_namespace() for opening the log stream of a specific + log namespace. systemd-journald also gained the ability to exit on + idle, which is useful in the context of log namespaces, as this means + log daemons for log namespaces can be activated automatically on + demand and will stop automatically when no longer used, minimizing + resource usage. + + * When systemd-tmpfiles copies a file tree using the 'C' line type it + will now label every copied file according to the SELinux database. + + * When systemd/PID 1 detects it is used in the initrd it will now boot + into initrd.target rather than default.target by default. This should + make it simpler to build initrds with systemd as for many cases the + only difference between a host OS image and an initrd image now is + the presence of the /etc/initrd-release file. + + * A new kernel command line option systemd.cpu_affinity= is now + understood. It's equivalent to the CPUAffinity= option in + /etc/systemd/system.conf and allows setting the CPU mask for PID 1 + itself and the default for all other processes. + + * When systemd/PID 1 is reloaded (with systemctl daemon-reload or + equivalent), the SELinux database is now reloaded, ensuring that + sockets and other file system objects are generated taking the new + database into account. + + * systemd/PID 1 accepts a new "systemd.show-status=error" setting, and + "quiet" has been changed to imply that instead of + "systemd.show-status=auto". In this mode, only messages about errors + and significant delays in boot are shown on the console. + + * The sd-event.h API gained native support for the new Linux "pidfd" + concept. This permits watching processes using file descriptors + instead of PID numbers, which fixes a number of races and makes + process supervision more robust and efficient. All of systemd's + components will now use pidfds if the kernel supports it for process + watching, with the exception of PID 1 itself, unfortunately. We hope + to move PID 1 to exclusively using pidfds too eventually, but this + requires some more kernel work first. (Background: PID 1 watches + processes using waitid() with the P_ALL flag, and that does not play + together nicely with pidfds yet.) + + * Closely related to this, the sd-event.h API gained two new calls + sd_event_source_send_child_signal() (for sending a signal to a + watched process) and sd_event_source_get_child_process_own() (for + marking a process so that it is killed automatically whenever the + event source watching it is freed). + + * systemd-networkd gained support for configuring Token Bucket Filter + (TBF) parameters in its qdisc configuration support. Similarly, + support for Stochastic Fairness Queuing (SFQ), Controlled-Delay + Active Queue Management (CoDel), and Fair Queue (FQ) has been added. + + * systemd-networkd gained support for Intermediate Functional Block + (IFB) network devices. + + * systemd-networkd gained support for configuring multi-path IP routes, + using the new MultiPathRoute= setting in the [Route] section. + + * systemd-networkd's DHCPv4 client has been updated to support a new + SendDecline= option. If enabled, duplicate address detection is done + after a DHCP offer is received from the server. If a conflict is + detected, the address is declined. The DHCPv4 client also gained + support for a new RouteMTUBytes= setting that allows to configure the + MTU size to be used for routes generated from DHCPv4 leases. + + * The PrefixRoute= setting in systemd-networkd's [Address] section of + .network files has been deprecated, and replaced by AddPrefixRoute=, + with its sense inverted. + + * The Gateway= setting of [Route] sections of .network files gained + support for a special new value "_dhcp". If set, the configured + static route uses the gateway host configured via DHCP. + + * New User= and SuppressPrefixLength= settings have been implemented + for the [RoutingPolicyRule] section of .network files to configure + source routing based on UID ranges and prefix length, respectively. + + * sd-bus gained a new API call sd_bus_message_sensitive() that marks a + D-Bus message object as "sensitive". Those objects are erased from + memory when they are freed. This concept is intended to be used for + messages that contain security sensitive data. A new flag + SD_BUS_VTABLE_SENSITIVE has been introduced as well to mark methods + in sd-bus vtables, causing any incoming and outgoing messages of + those methods to be implicitly marked as "sensitive". + + * sd-bus gained a new API call sd_bus_message_dump() for dumping the + contents of a message (or parts thereof) to standard output for + debugging purposes. + + * systemd-sysusers gained support for creating users with the primary + group named differently than the user. + + * systemd-resolved's DNS-over-TLS support gained SNI validation. + + * systemd-growfs (i.e. the x-systemd.growfs mount option in /etc/fstab) + gained support for growing XFS partitions. Previously it supported + only ext4 and btrfs partitions. + + * The support for /etc/crypttab gained a new x-initrd.attach option. If + set, the specified encrypted volume is unlocked already in the + initrd. This concept corresponds to the x-initrd.mount option in + /etc/fstab. + + * systemd-cryptsetup gained native support for unlocking encrypted + volumes utilizing PKCS#11 smartcards, i.e. for example to bind + encryption of volumes to YubiKeys. This is exposed in the new + pkcs11-uri= option in /etc/crypttab. + + * The /etc/fstab support in systemd now supports two new mount options + x-systemd.{required,wanted}-by=, for explicitly configuring the units + that the specified mount shall be pulled in by, in place of + the usual local-fs.target/remote-fs.target. + + * The https://systemd.io/ web site has been relaunched, directly + populated with most of the documentation included in the systemd + repository. systemd also acquired a new logo, thanks to Tobias + Bernard. + + * systemd-udevd gained support for managing "alternative" network + interface names, as supported by new Linux kernels. For the first + time this permits assigning multiple (and longer!) names to a network + interface. systemd-udevd will now by default assign the names + generated via all supported naming schemes to each interface. This + may be further tweaked with .link files and the AlternativeName= and + AlternativeNamesPolicy= settings. Other components of systemd have + been updated to support the new alternative names wherever + appropriate. For example, systemd-nspawn will now generate + alternative interface names for the host-facing side of container + veth links based on the full container name without truncation. + + * systemd-nspawn interface naming logic has been updated in another way + too: if the main interface name (i.e. as opposed to new-style + "alternative" names) based on the container name is truncated, a + simple hashing scheme is used to give different interface names to + multiple containers whose names all begin with the same prefix. Since + this changes the primary interface names pointing to containers if + truncation happens, the old scheme may still be requested by + selecting an older naming scheme, via the net.naming-scheme= kernel + command line option. + + * PrivateUsers= in service files now works in services run by the + systemd --user per-user instance of the service manager. + + * A new per-service sandboxing option ProtectClock= has been added that + locks down write access to the system clock. It takes away device + node access to /dev/rtc as well as the system calls that set the + system clock and the CAP_SYS_TIME and CAP_WAKE_ALARM capabilities. + Note that this option does not affect access to auxiliary services + that allow changing the clock, for example access to + systemd-timedated. + + * The systemd-id128 tool gained a new "show" verb for listing or + resolving a number of well-known UUIDs/128bit IDs, currently mostly + GPT partition table types. + + * The Discoverable Partitions Specification has been updated to support + /var and /var/tmp partition discovery. Support for this has been + added to systemd-gpt-auto-generator. For details see: + + https://systemd.io/DISCOVERABLE_PARTITIONS + + * "systemctl list-unit-files" has been updated to show a new column + with the suggested enablement state based on the vendor preset files + for the respective units. + + * "systemctl" gained a new option "--with-dependencies". If specified + commands such as "systemctl status" or "systemctl cat" will now show + all specified units along with all units they depend on. + + * networkctl gained support for showing per-interface logs in its + "status" output. + + * systemd-networkd-wait-online gained support for specifying the maximum + operational state to wait for, and to wait for interfaces to + disappear. + + * The [Match] section of .link and .network files now supports a new + option PermanentMACAddress= which may be used to check against the + permanent MAC address of a network device even if a randomized MAC + address is used. + + * The [TrafficControlQueueingDiscipline] section in .network files has + been renamed to [NetworkEmulator] with the "NetworkEmulator" prefix + dropped from the individual setting names. + + * Any .link and .network files that have an empty [Match] section (this + also includes empty and commented-out files) will now be + rejected. systemd-udev and systemd-networkd started warning about + such files in version 243. + + * systemd-logind will now validate access to the operation of changing + the virtual terminal via a PolicyKit action. By default, only users + with at least one session on a local VT are granted permission. + + * When systemd sets up PAM sessions that invoked service processes + shall run in, the pam_setcred() API is now invoked, thus permitting + PAM modules to set additional credentials for the processes. + + * portablectl attach/detach verbs now accept --now and --enable options + to combine attachment with enablement and invocation, or detachment + with stopping and disablement. + + Contributions from: AJ Bagwell, Alin Popa, Andreas Rammhold, Anita + Zhang, Ansgar Burchardt, Antonio Russo, Arian van Putten, Ashley Davis, + Balint Reczey, Bart Willems, Bastien Nocera, Benjamin Dahlhoff, Charles + (Chas) Williams, cheese1, Chris Down, Chris Murphy, Christian Ehrhardt, + Christian Göttsche, cvoinf, Daan De Meyer, Daniele Medri, Daniel Rusek, + Daniel Shahaf, Dann Frazier, Dan Streetman, Dariusz Gadomski, David + Michael, Dimitri John Ledkov, Emmanuel Bourg, Evgeny Vereshchagin, + ezst036, Felipe Sateler, Filipe Brandenburger, Florian Klink, Franck + Bui, Fran Dieguez, Frantisek Sumsal, Greg "GothAck" Miell, Guilhem + Lettron, Guillaume Douézan-Grard, Hans de Goede, HATAYAMA Daisuke, Iain + Lane, James Buren, Jan Alexander Steffens (heftig), Jérémy Rosen, Jin + Park, Jun'ichi Nomura, Kai Krakow, Kevin Kuehler, Kevin P. Fleming, + Lennart Poettering, Leonid Bloch, Leonid Evdokimov, lothrond, Luca + Boccassi, Lukas K, Lynn Kirby, Mario Limonciello, Mark Deneen, Matthew + Leeds, Michael Biebl, Michal Koutný, Michal Sekletár, Mike Auty, Mike + Gilbert, mtron, nabijaczleweli, Naïm Favier, Nate Jones, Norbert Lange, + Oliver Giles, Paul Davey, Paul Menzel, Peter Hutterer, Piotr Drąg, Rafa + Couto, Raphael, rhn, Robert Scheck, Rocka, Romain Naour, Ryan Attard, + Sascha Dewald, Shengjing Zhu, Slava Kardakov, Spencer Michaels, Sylvain + Plantefeve, Stanislav Angelovič, Susant Sahani, Thomas Haller, Thomas + Schmitt, Timo Schlüßler, Timo Wilken, Tobias Bernard, Tobias Klauser, + Tobias Stoeckmann, Topi Miettinen, tsia, WataruMatsuoka, Wieland + Hoffmann, Wilhelm Schuster, Will Fleming, xduugu, Yong Cong Sin, Yuri + Chornoivan, Yu Watanabe, Zach Smith, Zbigniew Jędrzejewski-Szmek, Zeyu + DONG + + – Warsaw, 2020-03-06 + CHANGES WITH 244: * Support for the cpuset cgroups v2 controller has been added. @@ -675,32 +984,33 @@ CHANGES WITH 243: Contributions from: Aaron Barany, Adrian Bunk, Alan Jenkins, Albrecht Lohofener, Andrej Valek, Anita Zhang, Arian van Putten, Balint Reczey, Bastien Nocera, Ben Boeckel, Benjamin Robin, camoz, Chen Qi, Chris - Chiu, Chris Down, Christian Kellner, Clinton Roy, Connor Reeder, Daniel - Black, Daniele Medri, Dan Streetman, Dave Reisner, Dave Ross, David - Art, David Tardon, Debarshi Ray, Dimitri John Ledkov, Dominick Grift, - Donald Buczek, Douglas Christman, Eric DeVolder, EtherGraf, Evgeny - Vereshchagin, Feldwor, Felix Riemann, Florian Dollinger, Francesco - Pennica, Franck Bui, Frantisek Sumsal, Franz Pletz, frederik, Hans - de Goede, Iago López Galeiras, Insun Pyo, Ivan Shapovalov, Iwan Timmer, - Jack, Jakob Unterwurzacher, Jan Chren, Jan Klötzke, Jan Losinski, Jan - Pokorný, Jan Synacek, Jan-Michael Brummer, Jeka Pats, Jeremy Soller, - Jérémy Rosen, Jiri Pirko, Joe Lin, Joerg Behrmann, Joe Richey, Jóhann - B. Guðmundsson, Johannes Christ, Johannes Schmitz, Jonathan Rouleau, - Jorge Niedbalski, Kai Krakow, Kai Lüke, Karel Zak, Kashyap Chamarthy, + Chiu, Chris Down, Christian Göttsche, Christian Kellner, Clinton Roy, + Connor Reeder, Daniel Black, Daniel Lublin, Daniele Medri, Dan + Streetman, Dave Reisner, Dave Ross, David Art, David Tardon, Debarshi + Ray, Dimitri John Ledkov, Dominick Grift, Donald Buczek, Douglas + Christman, Eric DeVolder, EtherGraf, Evgeny Vereshchagin, Feldwor, + Felix Riemann, Florian Dollinger, Francesco Pennica, Franck Bui, + Frantisek Sumsal, Franz Pletz, frederik, Hans de Goede, Iago López + Galeiras, Insun Pyo, Ivan Shapovalov, Iwan Timmer, Jack, Jakob + Unterwurzacher, Jan Chren, Jan Klötzke, Jan Losinski, Jan Pokorný, Jan + Synacek, Jan-Michael Brummer, Jeka Pats, Jeremy Soller, Jérémy Rosen, + Jiri Pirko, Joe Lin, Joerg Behrmann, Joe Richey, Jóhann B. Guðmundsson, + Johannes Christ, Johannes Schmitz, Jonathan Rouleau, Jorge Niedbalski, + Jörg Thalheim, Kai Krakow, Kai Lüke, Karel Zak, Kashyap Chamarthy, Krayushkin Konstantin, Lennart Poettering, Lubomir Rintel, Luca Boccassi, Luís Ferreira, Marc-André Lureau, Markus Felten, Martin Pitt, Matthew Leeds, Mattias Jernberg, Michael Biebl, Michael Olbrich, Michael Prokop, Michael Stapelberg, Michael Zhivich, Michal Koutný, Michal Sekletar, Mike Gilbert, Milan Broz, Miroslav Lichvar, mpe85, Mr-Foo, Network Silence, Oliver Harley, pan93412, Paul Menzel, pEJipE, - Peter A. Bigot, Philip Withnall, Piotr Drąg, Rafael Fontenelle, Roberto - Santalla, Ronan Pigott, root, RussianNeuroMancer, Sebastian Jennen, - shinygold, Shreyas Behera, Simon Schricker, Susant Sahani, Thadeu Lima - de Souza Cascardo, Theo Ouzhinski, Thiebaud Weksteen, Thomas Haller, - Thomas Weißschuh, Tomas Mraz, Tommi Rantala, Topi Miettinen, VD-Lycos, - ven, Wieland Hoffmann, William A. Kennington III, William Wold, Xi - Ruoyao, Yuri Chornoivan, Yu Watanabe, Zach Smith, Zbigniew - Jędrzejewski-Szmek, Zhang Xianwei + Peter A. Bigot, Philip Withnall, Piotr Drąg, Rafael Fontenelle, Robert + Scheck, Roberto Santalla, Ronan Pigott, root, RussianNeuroMancer, + Sebastian Jennen, shinygold, Shreyas Behera, Simon Schricker, Susant + Sahani, Thadeu Lima de Souza Cascardo, Theo Ouzhinski, Thiebaud + Weksteen, Thomas Haller, Thomas Weißschuh, Tomas Mraz, Tommi Rantala, + Topi Miettinen, VD-Lycos, ven, Vladimir Yerilov, Wieland Hoffmann, + William A. Kennington III, William Wold, Xi Ruoyao, Yuri Chornoivan, + Yu Watanabe, Zach Smith, Zbigniew Jędrzejewski-Szmek, Zhang Xianwei – Camerino, 2019-09-03 @@ -6914,10 +7224,9 @@ CHANGES WITH 213: * A new fsck.repair= kernel option has been added to control how fsck shall deal with unclean file systems at boot. - * The (.ini) configuration file parser will now silently - ignore sections whose name begins with "X-". This may be - used to maintain application-specific extension sections in unit - files. + * The (.ini) configuration file parser will now silently ignore + sections whose names begin with "X-". This may be used to maintain + application-specific extension sections in unit files. * machined gained a new API to query the IP addresses of registered containers. "machinectl status" has been updated diff --git a/README.md b/README.md index 0ba648a82..0274715e8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -![systemd logo](http://brand.systemd.io/assets/page-logo.png) +![Systemd](http://brand.systemd.io/assets/page-logo.png) -# systemd - System and Service Manager +System and Service Manager Count of open issues over time Count of open pull requests over time diff --git a/TODO b/TODO index c2ee593ef..e944245a5 100644 --- a/TODO +++ b/TODO @@ -17,18 +17,111 @@ Janitorial Clean-ups: * rework mount.c and swap.c to follow proper state enumeration/deserialization semantics, like we do for device.c now -Before v244: - -* revisit SystemdOptions EFI variable. Find a better, systematic name and use - it for the env var, the bootctl verb and the EFI variable itself, clear up - semantics. - Features: +* cryptsetup/homed: also support FIDO2 HMAC password logic for unlocking + devices. (see: https://github.com/mjec/fido2-hmac-secret) + +* systemd-gpt-auto should probably set x-systemd.growfs on the mounts it + creates + +* homed/userdb: distuingish passwords and recovery keys in the records, since + we probably want to use different PBKDF algorithms/settings for them: + passwords have low entropy but recovery keys should have good entropy key + hence we can make them quicker to work. + +* bootctl: + - teach it to prepare an ESP wholesale, i.e. with mkfs.vfat invocation + - teach it to copy in unified kernel images and maybe type #1 boot loader spec entries from host + - make it operate on loopback files, dissecting enough to find ESP to operate on + +* by default, in systemd --user service bump the OOMAdjust to 100, as privs + allow so that systemd survives + +* honour specifiers in unit files that resolve to some very basic + /etc/os-release data, such as ID, VERSION_ID, BUILD_ID, VARIANT_ID. + +* cryptsetup: allow encoding key directly in /etc/crypttab, maybe with a + "base64:" prefix. Useful in particular for pkcs11 mode. + +* cryptsetup: reimplement the mkswap/mke2fs in cryptsetup-generator to use + systemd-makefs.service instead. + * socket units: allow creating a udev monitor socket with ListenDevices= or so, with matches, then actviate app thorugh that passing socket oveer -* move discoverable partitions spec into markdown and our tree +* unify on openssl: + - port sd_id128_get_machine_app_specific() over from khash + - port resolved over from libgcrypt (DNSSEC code) + - port journald + fsprg over from libgcrypt + - port importd over from libgcrypt + - when that's done: kill khash.c + - when that's done: kill gnutls support in resolved + +* kill zenata, all hail weblate? + +* when we resize disks (homed?) always round up to 4K sectors, not 512K + +* add growvol and makevol options for /etc/crypttab, similar to + x-systemd.growfs and x-systemd-makefs. + +* hook up the TPM to /etc/crypttab, with a new option that is similar to the + new PKCS#11 option in crypttab, and allows unlocking a LUKS volume via a key + unsealed from the TPM. Optionally, if TPM is not available fall back to + TPM-less mode, and set up linear DM mapping instead (inspired by kpartx), so + that the device paths stay the same, regardless if crypto is used or not. + +* systemd-repart: by default generate minimized partition tables (i.e. tables + that only covere the space actually used, excluding any free space at the + end), in order to maximize dd'ability. Requires libfdisk work, see + https://github.com/karelzak/util-linux/issues/907 + +* systemd-repart: optionally, allow specifiying a path to initialize new + partitions from, i.e. an fs image file or a source device node. This would + then turn systemd-repart into a simple installer: with a few .repart files + you could replicate the host system on another device. a full installer would + then be: "systemd-repart /dev/sda && bootctl install /dev/sda && + systemd-firstboot --image= …" + +* systemd-repart: MBR partition table support. Care needs to be taken regarding + Type=, so that partition definitions can sanely apply to both the GPT and the + MBR case. Idea: accept syntax "Type=gpt:home mbr:0x83" for setting the types + for the two partition types explicitly. And provide an internal mapping so + that "Type=linux-generic" maps to the right types for both partition tables + automatically. + +* systemd-repart: allow sizing partitions as factor of available RAM, so that + we can reasonably size swap partitions for hibernation. + +* systemd-repart: allow running mkfs before making partitions pop up + + encryption via LUKS to allow booting into an empty root with only /usr mounted in + +* systemd-repart: allow managing the gpt read-only partition flag + auto-mount flag + +* systemd-repart: allow disabling growing of specific partitions, or making + them (think ESP: we don't ever want to grow it, since we cannot resize vfat) + +* systemd-repart: add specifier expansion, add especifier that refers to root + device node of current system, /usr device node, and matching verity, so that + an installer can be made a "copy" installer of the booted OS + +* systemd-repart: make it a static checker during early boot for existence and + absence of other partitions for trusted boot environments + +* systemd-repart: when no configuration is found, exit early do not check + partition table, so that it is safe to run in the initrd on any system + +* systemd-repart: allow config of partition uuid + +* userdb: allow username prefix searches in varlink API + +* userdb: allow existence checks + +* pid: activation by journal search expression + +* when switching root from initrd to host, set the machine_id env var so that + if the host has no machine ID set yet we continue to use the random one the + initrd had set. * sd-event: add native support for P_ALL waitid() watching, then move PID 1 to it fo reaping assigned but unknown children. This needs to some special care @@ -41,8 +134,6 @@ Features: waitid() only on the children with the highest priority until one is waitable and ignore all lower-prio ones from that point on -* sd-event: drop stack allocated epoll_event buffer in sd_event_wait() - * maybe introduce xattrs that can be set on the root dir of the root fs partition that declare the volatility mode to use the image in. Previously I thought marking this via GPT partition flags but that's not ideal since @@ -50,8 +141,6 @@ Features: shouldn't operate in a volatile mode unless we got told so from a trusted source. -* look for /var/tmp automatically via gpt auto discovery - * figure out automatic partition discovery when combining writable root dir with immutable /usr @@ -84,10 +173,6 @@ Features: right) become genuine first class citizens, and we gain automatic, sane JSON output for them. -* dissector: invoke fsck on the file systems we encounter, after all ext4 is - still pretty popular (and we mount the ESP too with it after all, which is - fat) - * systemd-firstboot: teach it dissector magic, so that you can point it to some disk image and it will just set everything in it all behind the scenes. @@ -110,6 +195,38 @@ Features: user@.service, which returns the XDG_RUNTIME_DIR value, and make this behaviour selectable via pam module option. +* homed: + - when user tries to log into record signed by unrecognized key, automatically add key to our chain after polkit auth + - hook up machined/nspawn users with a varlink user query interface + - rollback when resize fails mid-operation + - GNOME's side for forget key on suspend (requires rework so that lock screen runs outside of uid) + - resize on login? + - fstrim on logout? + - shrink fs on logout? + - update LUKS password on login if we find there's a password that unlocks the JSON record but not the LUKS device. + - create on activate? + - properties: icon url?, preferred session type?, administrator bool (which translates to 'wheel' membership)?, address?, telephone?, vcard?, samba stuff?, parental controls? + - communicate clearly when usb stick is safe to remove. probably involves + beefing up logind to make pam session close hook synchronous and wait until + systemd --user is shut down. + - logind: maybe keep a "busy fd" as long as there's a non-released session around or the user@.service + - maybe make automatic, read-only, time-based reflink-copies of LUKS disk images (think: time machine) + - distuingish destroy / remove (i.e. currently we can unregister a user, unregister+remove their home directory, but not just remove their home directory) + - in systemd's PAMName= logic: query passwords with ssh-askpassword, so that we can make "loginctl set-linger" mode work + - fingerprint authentication, pattern authentication, … + - make sure "classic" user records can also be managed by homed + - description field for groups + - make size of $XDG_RUNTIME_DIR configurable in user record + - reuse pwquality magic in firstboot + - query password from kernel keyring first + - update even if record is "absent" + - add a "access mode" + "fstype" field to the "status" section of json identity records reflecting the actually used access mode and fstype, even on non-luks backends + - move acct mgmt stuff from pam_systemd_home to pam_systemd? + - when "homectl --pkcs11-token-uri=" is used, synthesize ssh-authorized-keys records for all keys we have private keys on the stick for + - make slice for users configurable (requires logind rework) + - logind: populate auto-login list bus property from PKCS#11 token + - when determining state of a LUKS home directory, check DM suspended sysfs file + * introduce a new per-process uuid, similar to the boot id, the machine id, the invocation id, that is derived from process creds, specifically a hashed combination of AT_RANDOM + getpid() + the starttime from @@ -180,13 +297,6 @@ Features: * introduce per-unit (i.e. per-slice, per-service) journal log size limits. -* optionally, if a per-partition GPT flag is set for the root/home/… partitions - format the partition on next boot and unset the flag, in order to implement - factory reset. also, add a second flag that simply indicates whether such a - scheme is supported. then, add a tool (or maybe beef up systemd-dissect) to - show state of these flags, and optionally trigger such a factory reset on - next boot by setting the flag. - * sd-boot: automatically load EFI modules from some drop-in dir, so that people can add in file system drivers and such @@ -238,7 +348,7 @@ Features: 1. add resume_offset support to the resume code (i.e. support swap files properly) 2. check if swap is on weird storage and refuse if so - 3. add autodetection of hibernation images + 3. add auto-detection of hibernation images * cgroups: use inotify to get notified when somebody else modifies cgroups owned by us, then log a friendly warning. @@ -382,8 +492,6 @@ Features: * show whether a service has out-of-date configuration in "systemctl status" by using mtime data of ConfigurationDirectory=. -* replace all remaining uses of fgets() + LINE_MAX by read_line() - * Add AddUser= setting to unit files, similar to DynamicUser=1 which however creates a static, persistent user rather than a dynamic, transient user. We can leverage code from sysusers.d for this. @@ -402,10 +510,6 @@ Features: yogas can be recognized as "convertible" too, even if they predate the DMI "convertible" form factor -* Maybe add a small tool invoked early at boot, that adds in or resizes - partitions automatically, to be used when the media used is actually larger - than the image written onto it is. - * Maybe add PrivatePIDs= as new unit setting, and do minimal PID namespacing after all. Be strict however, only support the equivalent of nspawn's --as-pid2 switch, and sanely proxy sd_notify() messages dropping stuff such @@ -424,24 +528,6 @@ Features: "systemd-gdb" for attaching to the start-up of any system service in its natural habitat. -* maybe introduce gpt auto discovery for /var/tmp? - -* maybe add gpt-partition-based user management: each user gets his own - LUKS-encrypted GPT partition with a new GPT type. A small nss module - enumerates users via udev partition enumeration. UIDs are assigned in a fixed - way: the partition index is added as offset to some fixed base uid. User name - is stored in GPT partition name. A PAM module authenticates the user via the - LUKS partition password. Benefits: strong per-user security, compatibility - with stateless/read-only/verity-enabled root. (other idea: do this based on - loopback files in /home, without GPT involvement) - -* gpt-auto logic: introduce support for discovering /var matching an image. For - that, use a partition type UUID that is hashed from the OS name (as encoded - in /etc/os-release), the architecture, and 4 new bits from the gpt flags - field of the root partition. This way can easily support multiple OS - installations on the same GPT partition table, without problems with - unmatched /var partitions. - * gpt-auto logic: related to the above, maybe support a "secondary" root partition, that is mounted to / and is writable, and where the actual root's /usr is mounted into. @@ -464,8 +550,6 @@ Features: * define gpt header bits to select volatility mode -* ProtectKernelLogs= (drops CAP_SYSLOG, add seccomp for syslog() syscall, and DeviceAllow to /dev/kmsg) in service files - * ProtectClock= (drops CAP_SYS_TIMES, adds seecomp filters for settimeofday, adjtimex), sets DeviceAllow o /dev/rtc * ProtectTracing= (drops CAP_SYS_PTRACE, blocks ptrace syscall, makes /sys/kernel/tracing go away) @@ -523,7 +607,7 @@ Features: * when we detect that there are waiting jobs but no running jobs, do something -* push CPUAffinity= also into the "cpuset" cgroup controller (only after the cpuset controller got ported to the unified hierarchy) +* push CPUAffinity= also into the "cpuset" cgroup controller * PID 1 should send out sd_notify("WATCHDOG=1") messages (for usage in the --user mode, and when run via nspawn) @@ -566,8 +650,6 @@ Features: * as soon as we have sender timestamps, revisit coalescing multiple parallel daemon reloads: http://lists.freedesktop.org/archives/systemd-devel/2014-December/025862.html -* in systemctl list-unit-files: show the install value the presets would suggest for a service in a third column - * figure out when we can use the coarse timers * add "systemctl start -v foobar.service" that shows logs of a service @@ -584,8 +666,6 @@ Features: * what to do about udev db binary stability for apps? (raw access is not an option) -* man: maybe use the word "inspect" rather than "introspect"? - * systemctl: if some operation fails, show log output? * systemctl edit: use equivalent of cat() to insert existing config as a comment, prepended with #. @@ -597,9 +677,6 @@ Features: * merge ~/.local/share and ~/.local/lib into one similar /usr/lib and /usr/share.... -* systemd.show_status= should probably have a mode where only failed - units are shown. - * add systemd.abort_on_kill or some other such flag to send SIGABRT instead of SIGKILL (throughout the codebase, not only PID1) @@ -705,7 +782,6 @@ Features: - allow multiple signal handlers per signal? - document chaining of signal handler for SIGCHLD and child handlers - define more intervals where we will shift wakeup intervals around in, 1h, 6h, 24h, ... - - generate a failure of a default event loop is executed out-of-thread * investigate endianness issues of UUID vs. GUID @@ -818,11 +894,6 @@ Features: - journald: when we drop syslog messages because the syslog socket is full, make sure to write how many messages are lost as first thing to syslog when it works again. - - change systemd-journal-flush into a service that stays around during - boot, and causes the journal to be moved back to /run on shutdown, - so that we do not keep /var busy. This needs to happen synchronously, - hence doing this via signals is not going to work. - - optionally support running journald from the command line for testing purposes in external projects - journald: allow per-priority and per-service retention times when rotating/vacuuming - journald: make use of uid-range.h to managed uid ranges to split journals in. @@ -1044,8 +1115,6 @@ Features: - allow Type=simple with PIDFile= https://bugzilla.redhat.com/show_bug.cgi?id=723942 - allow writing multiple conditions in unit files on one line - - load-fragment: when loading a unit file via a chain of symlinks - verify that it is not masked via any of the names traversed. - introduce Type=pid-file - introduce mix of BindTo and Requisite - add a concept of RemainAfterExit= to scope units @@ -1154,4 +1223,3 @@ Regularly: * link up selected blog stories from man pages and unit files Documentation= fields String is not UTF-8 clean, ignoring assignment - timedatex.service: Consumed 26ms CPU time. diff --git a/configure b/configure index a9db8a1cf..5247074b6 100755 --- a/configure +++ b/configure @@ -1,4 +1,5 @@ -#!/bin/bash -e +#!/usr/bin/env bash +set -e cflags=CFLAGS="$CFLAGS" cxxflags=CXXFLAGS="$CXXFLAGS" diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 000000000..ca35be08d --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +_site diff --git a/docs/AUTOMATIC_BOOT_ASSESSMENT.md b/docs/AUTOMATIC_BOOT_ASSESSMENT.md index 1ef4bdcfe..aff203b59 100644 --- a/docs/AUTOMATIC_BOOT_ASSESSMENT.md +++ b/docs/AUTOMATIC_BOOT_ASSESSMENT.md @@ -1,5 +1,7 @@ --- title: Automatic Boot Assessment +category: Booting +layout: default --- # Automatic Boot Assessment @@ -54,7 +56,7 @@ components: script can optionally create boot loader entries that carry an initial boot counter (the initial counter is configurable in `/etc/kernel/tries`). -# Details +## Details The boot counting data `systemd-boot` and `systemd-bless-boot.service` manage is stored in the name of the boot loader entries. If a boot loader entry @@ -147,7 +149,7 @@ scenario the first 4 steps are the same as above: 12. On the following boot (and all subsequent boots after that) the entry is now seen with boot counting turned off, no further renaming takes place. -# How to adapt this scheme to other setups +## How to adapt this scheme to other setups Of the stack described above many components may be replaced or augmented. Here are a couple of recommendations. @@ -178,7 +180,7 @@ are a couple of recommendations. wrap them in a unit and order them after `boot-complete.target`, pulling it in. -# FAQ +## FAQ 1. *Why do you use file renames to store the counter? Why not a regular file?* — Mainly two reasons: it's relatively likely that renames can be implemented diff --git a/docs/BLOCK_DEVICE_LOCKING.md b/docs/BLOCK_DEVICE_LOCKING.md index 5509b4194..f122eda41 100644 --- a/docs/BLOCK_DEVICE_LOCKING.md +++ b/docs/BLOCK_DEVICE_LOCKING.md @@ -1,5 +1,7 @@ --- title: Locking Block Device Access +category: Interfaces +layout: default --- # Locking Block Device Access diff --git a/docs/BOOT_LOADER_INTERFACE.md b/docs/BOOT_LOADER_INTERFACE.md index c0ed09984..6084fe2a2 100644 --- a/docs/BOOT_LOADER_INTERFACE.md +++ b/docs/BOOT_LOADER_INTERFACE.md @@ -1,5 +1,7 @@ --- -title: The Boot Loader Interface +title: Boot Loader Interface +category: Booting +layout: default --- # The Boot Loader Interface @@ -140,3 +142,11 @@ names for them in UIs. 6. If a boot menu entry encapsulates a reboot into EFI firmware setup feature, it should use the identifier `reboot-to-firmware-setup` (or `auto-reboot-to-firmware-setup` in case it is automatically discovered). + +## Links + +[Boot Loader Specification](https://systemd.io/BOOT_LOADER_INTERFACE)
+[Discoverable Partitions Specification](https://systemd.io/DISCOVERABLE_PARTITIONS)
+[systemd-boot(7)](https://www.freedesktop.org/software/systemd/man/systemd-boot.html)
+[bootctl(1)](https://www.freedesktop.org/software/systemd/man/bootctl.html)
+[systemd-gpt-auto-generator(8)](https://www.freedesktop.org/software/systemd/man/systemd-gpt-auto-generator.html) diff --git a/docs/BOOT_LOADER_SPECIFICATION.md b/docs/BOOT_LOADER_SPECIFICATION.md index 3bd300c24..514b8cd11 100644 --- a/docs/BOOT_LOADER_SPECIFICATION.md +++ b/docs/BOOT_LOADER_SPECIFICATION.md @@ -1,5 +1,7 @@ --- -title: The Boot Loader Specification +title: Boot Loader Specification +category: Booting +layout: default --- # The Boot Loader Specification @@ -53,14 +55,14 @@ functionality. Here's why we think that it is not enough for our uses: Everything described below is located on a placeholder file system `$BOOT`. The installer program should pick `$BOOT` according to the following rules: -* On disks with MBR disk labels - * If the OS is installed on a disk with MBR disk label, and a partition with the MBR type id of 0xEA already exists it should be used as `$BOOT`. - * Otherwise, if the OS is installed on a disk with MBR disk label, a new partition with MBR type id of 0xEA shall be created, of a suitable size (let's say 500MB), and it should be used as `$BOOT`. -* On disks with GPT disk labels - * If the OS is installed on a disk with GPT disk label, and a partition with the GPT type GUID of `bc13c2ff-59e6-4262-a352-b275fd6f7172` already exists, it should be used as `$BOOT`. - * Otherwise, if the OS is installed on a disk with GPT disk label, and an ESP partition (i.e. with the GPT type UID of `c12a7328-f81f-11d2-ba4b-00a0c93ec93b`) already exists and is large enough (let's say 250MB`) and otherwise qualifies, it should be used as `$BOOT`. - * Otherwise, if the OS is installed on a disk with GPT disk label, and if the ESP partition already exists but is too small, a new suitably sized (let's say 500MB) partition with GPT type GUID of `bc13c2ff-59e6-4262-a352-b275fd6f7172` shall be created and it should be used as `$BOOT`. - * Otherwise, if the OS is installed on a disk with GPT disk label, and no ESP partition exists yet, a new suitably sized (let's say 500MB) ESP should be created and should be used as `$BOOT`. +* On disks with an MBR partition table: + * If the OS is installed on a disk with an MBR partition table, and a partition with the type id of 0xEA already exists it should be used as `$BOOT`. + * Otherwise, if the OS is installed on a disk with an MBR partition table, a new partition with type id of 0xEA shall be created, of a suitable size (let's say 500MB), and it should be used as `$BOOT`. +* On disks with GPT (GUID Partition Table) + * If the OS is installed on a disk with GPT, and an Extended Boot Loader Partition or XBOOTLDR partition for short, i.e. a partition with GPT type GUID of `bc13c2ff-59e6-4262-a352-b275fd6f7172`, already exists, it should be used as `$BOOT`. + * Otherwise, if the OS is installed on a disk with GPT, and an EFI System Partition or ESP for short, i.e. a partition with GPT type UID of `c12a7328-f81f-11d2-ba4b-00a0c93ec93b`) already exists and is large enough (let's say 250MB) and otherwise qualifies, it should be used as `$BOOT`. + * Otherwise, if the OS is installed on a disk with GPT, and if the ESP partition already exists but is too small, a new suitably sized (let's say 500MB) XBOOTLDR partition shall be created and used as `$BOOT`. + * Otherwise, if the OS is installed on a disk with GPT, and no ESP partition exists yet, a new suitably sized (let's say 500MB) ESP should be created and used as `$BOOT`. This placeholder file system shall be determined during _installation time_, and an fstab entry may be created. It should be mounted to either `/boot/` or `/efi/`. Additional locations like `/boot/efi/`, with `/boot/` being a separate file system, might be supported by implementations. This is not recommended because the mounting of `$BOOT` is then dependent on and requires the mounting of the intermediate file system. @@ -89,6 +91,20 @@ from the user. Only entries matching the feature set of boot loader and system shall be considered and displayed. This allows image builders to put together images that transparently support multiple different architectures. +Note that the `$BOOT` partition is not supposed to be exclusive territory of +this specification. This specification only defines semantics of the `/loader/` +directory inside the file system (see below), but it doesn't intend to define +ownership of the whole file system exclusively. Boot loaders, firmware, and +other software implementating this specification may choose to place other +files and directories in the same file system. For example, boot loaders that +implement this specification might install their own boot code into the `$BOOT` +partition. On systems where `$BOOT` is the ESP this is a particularly common +setup. Implementations of this specification must be able to operate correctly +if files or directories other than `/loader/` are found in the top level +directory. Implementations that add their own files or directories to the file +systems should use well-named directories, to make name collisions between +multiple users of the file system unlikely. + ### Type #1 Boot Loader Specification Entries We define two directories below `$BOOT`: @@ -218,5 +234,9 @@ There are a couple of items that are out of focus for this specification: ## Links +[GUID Partition Table](https://en.wikipedia.org/wiki/GUID_Partition_Table)
+[Boot Loader Interface](https://systemd.io/BOOT_LOADER_INTERFACE)
+[Discoverable Partitions Specification](https://systemd.io/DISCOVERABLE_PARTITIONS)
[systemd-boot(7)](https://www.freedesktop.org/software/systemd/man/systemd-boot.html)
-[bootctl(1)](https://www.freedesktop.org/software/systemd/man/bootctl.html) +[bootctl(1)](https://www.freedesktop.org/software/systemd/man/bootctl.html)
+[systemd-gpt-auto-generator(8)](https://www.freedesktop.org/software/systemd/man/systemd-gpt-auto-generator.html) diff --git a/docs/CGROUP_DELEGATION.md b/docs/CGROUP_DELEGATION.md index 607ba6f81..d05503bc9 100644 --- a/docs/CGROUP_DELEGATION.md +++ b/docs/CGROUP_DELEGATION.md @@ -1,5 +1,7 @@ --- title: Control Group APIs and Delegation +category: Interfaces +layout: default --- # Control Group APIs and Delegation @@ -19,10 +21,10 @@ comprehensive up-to-date information about all this, particular in light of the poor implementations of the components interfacing with systemd of current container managers. -Before you read on, please make sure you read the low-level [kernel -documentation about -cgroup v2](https://www.kernel.org/doc/Documentation/cgroup-v2.txt). This -documentation then adds in the higher-level view from systemd. +Before you read on, please make sure you read the low-level kernel +documentation about the +[unified cgroup hierarchy](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html). +This document then adds in the higher-level view from systemd. This document augments the existing documentation we already have: diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md index da290ecda..b906bf5ac 100644 --- a/docs/CODE_OF_CONDUCT.md +++ b/docs/CODE_OF_CONDUCT.md @@ -1,5 +1,7 @@ --- -title: The systemd Community Conduct Guidelines +title: systemd Community Conduct Guidelines +category: Contributing +layout: default --- # The systemd Community Conduct Guidelines diff --git a/docs/CODE_QUALITY.md b/docs/CODE_QUALITY.md index a3bdfaad8..9f261474a 100644 --- a/docs/CODE_QUALITY.md +++ b/docs/CODE_QUALITY.md @@ -1,5 +1,7 @@ --- title: Code Quality Tools +category: Contributing +layout: default --- # Code Quality Tools diff --git a/docs/CODING_STYLE.md b/docs/CODING_STYLE.md index 3b9b5e6c4..c8ca8bfef 100644 --- a/docs/CODING_STYLE.md +++ b/docs/CODING_STYLE.md @@ -1,5 +1,7 @@ --- title: Coding Style +category: Contributing +layout: default --- # Coding Style @@ -541,7 +543,7 @@ title: Coding Style time you need that please immediately undefine `basename()`, and add a comment about it, so that no code ever ends up using the POSIX version! -# Committing to git +## Committing to git - Commit message subject lines should be prefixed with an appropriate component name of some kind. For example "journal: ", "nspawn: " and so on. diff --git a/docs/CONTAINER_INTERFACE.md b/docs/CONTAINER_INTERFACE.md new file mode 100644 index 000000000..71f9185c5 --- /dev/null +++ b/docs/CONTAINER_INTERFACE.md @@ -0,0 +1,290 @@ +--- +title: Container Interface +category: Interfaces +layout: default +--- + +# The Container Interface + +Also consult [Writing Virtual Machine or Container +Managers](http://www.freedesktop.org/wiki/Software/systemd/writing-vm-managers). + +systemd has a number of interfaces for interacting with container managers, +when systemd is used inside of an OS container. If you work on a container +manager, please consider supporting the following interfaces. + +## Execution Environment + +1. If the container manager wants to control the hostname for a container + running systemd it may just set it before invoking systemd, and systemd will + leave it unmodified when there is no hostname configured in `/etc/hostname` + (that file overrides whatever is pre-initialized by the container manager). + +2. Make sure to pre-mount `/proc/`, `/sys/`, and `/sys/fs/selinux/` before + invoking systemd, and mount `/proc/sys/`, `/sys/`, and `/sys/fs/selinux/` + read-only in order to prevent the container from altering the host kernel's + configuration settings. (As a special exception, if your container has + network namespaces enabled, feel free to make `/proc/sys/net/` writable). + systemd and various other subsystems (such as the SELinux userspace) have + been modified to behave accordingly when these file systems are read-only. + (It's OK to mount `/sys/` as `tmpfs` btw, and only mount a subset of its + sub-trees from the real `sysfs` to hide `/sys/firmware/`, `/sys/kernel/` and + so on. If you do that, make sure to mark `/sys/` read-only, as that + condition is what systemd looks for, and is what is considered to be the API + in this context.) + +3. Pre-mount `/dev/` as (container private) `tmpfs` for the container and bind + mount some suitable TTY to `/dev/console`. Also, make sure to create device + nodes for `/dev/null`, `/dev/zero`, `/dev/full`, `/dev/random`, + `/dev/urandom`, `/dev/tty`, `/dev/ptmx` in `/dev/`. It is not necessary to + create `/dev/fd` or `/dev/stdout`, as systemd will do that on its own. Make + sure to set up a `BPF_PROG_TYPE_CGROUP_DEVICE` BPF program — on cgroupv2 — + or the `devices` cgroup controller — on cgroupv1 — so that no other devices + but these may be created in the container. Note that many systemd services + use `PrivateDevices=`, which means that systemd will set up a private + `/dev/` for them for which it needs to be able to create these device nodes. + Dropping `CAP_MKNOD` for containers is hence generally not advisable, but + see below. + +4. `systemd-udevd` is not available in containers (and refuses to start), and + hence device dependencies are unavailable. The `systemd-udevd` unit files + will check for `/sys/` being read-only, as an indication whether device + management can work. Therefore make sure to mount `/sys/` read-only in the + container (see above). Various clients of `systemd-udevd` also check the + read-only state of `/sys/`, including PID 1 itself and `systemd-networkd`. + +5. If systemd detects it is run in a container it will spawn a single shell on + `/dev/console`, and not care about VTs or multiple gettys on VTs. (But see + `$container_ttys` below.) + +6. Either pre-mount all cgroup hierarchies in full into the container, or leave + that to systemd which will do so if they are missing. Note that it is + explicitly *not* OK to just mount a sub-hierarchy into the container as that + is incompatible with `/proc/$PID/cgroup` (which lists full paths). Also the + root-level cgroup directories tend to be quite different from inner + directories, and that distinction matters. It is OK however, to mount the + "upper" parts read-only of the hierarchies, and only allow write-access to + the cgroup sub-tree the container runs in. It's also a good idea to mount + all controller hierarchies with exception of `name=systemd` fully read-only + (this only applies to cgroupv1, of course), to protect the controllers from + alteration from inside the containers. Or to turn this around: only the + cgroup sub-tree of the container itself (on cgroupv2 in the unified + hierarchy, and on cgroupv1 in the `name=systemd` hierarchy) may be writable + to the container. + +7. Create the control group root of your container by either running your + container as a service (in case you have one container manager instance per + container instance) or creating one scope unit for each container instance + via systemd's transient unit API (in case you have one container manager + that manages all instances. Either way, make sure to set `Delegate=yes` in + it. This ensures that that the unit you created will be part of all cgroup + controllers (or at least the ones systemd understands). The latter may also + be done via `systemd-machined`'s `CreateMachine()` API. Make sure to use the + cgroup path systemd put your process in for all operations of the container. + Do not add new cgroup directories to the top of the tree. This will not only + confuse systemd and the admin, but also prevent your implementation from + being "stackable". + +## Environment Variables + +1. To allow systemd (and other programs) to identify that it is executed within + a container, please set the `$container` environment variable for PID 1 in + the container to a short lowercase string identifying your + implementation. With this in place the `ConditionVirtualization=` setting in + unit files will work properly. Example: `container=lxc-libvirt` + +2. systemd has special support for allowing container managers to initialize + the UUID for `/etc/machine-id` to some manager supplied value. This is only + enabled if `/etc/machine-id` is empty (i.e. not yet set) at boot time of the + container. The container manager should set `$container_uuid` as environment + variable for the container's PID 1 to the container UUID. (This is similar + to the effect of `qemu`'s `-uuid` switch). Note that you should pass only a + UUID here that is actually unique (i.e. only one running container should + have a specific UUID), and gets changed when a container gets duplicated. + Also note that systemd will try to persistently store the UUID in + `/etc/machine-id` (if writable) when this option is used, hence you should + always pass the same UUID here. Keeping the externally used UUID for a + container and the internal one in sync is hopefully useful to minimize + surprise for the administrator. + +3. systemd can automatically spawn login gettys on additional ptys. A container + manager can set the `$container_ttys` environment variable for the + container's PID 1 to tell it on which ptys to spawn gettys. The variable + should take a space separated list of pty names, without the leading `/dev/` + prefix, but with the `pts/` prefix included. Note that despite the + variable's name you may only specify ptys, and not other types of ttys. Also + you need to specify the pty itself, a symlink will not suffice. This is + implemented in + [systemd-getty-generator(8)](https://www.freedesktop.org/software/systemd/man/systemd-getty-generator.html). + Note that this variable should not include the pty that `/dev/console` maps + to if it maps to one (see below). Example: if the container receives + `container_ttys=pts/7 pts/8 pts/14` it will spawn three additional login + gettys on ptys 7, 8, and 14. + +## Advanced Integration + +1. Consider syncing `/etc/localtime` from the host file system into the + container. Make it a relative symlink to the containers's zoneinfo dir, as + usual. Tools rely on being able to determine the timezone setting from the + symlink value, and making it relative looks nice even if people list the + container's `/etc/` from the host. + +2. Make the container journal available in the host, by automatically + symlinking the container journal directory into the host journal directory. + More precisely, link `/var/log/journal/` of the + container into the same dir of the host. Administrators can then + automatically browse all container journals (correctly interleaved) by + issuing `journalctl -m`. The container machine ID can be determined from + `/etc/machine-id` in the container. + +3. If the container manager wants to cleanly shutdown the container, it might + be a good idea to send `SIGRTMIN+3` to its init process. systemd will then + do a clean shutdown. Note however, that since only systemd understands + `SIGRTMIN+3` like this, this might confuse other init systems. + +4. To support [Socket Activated + Containers](http://0pointer.de/blog/projects/socket-activated-containers.html) + the container manager should be capable of being run as a systemd + service. It will then receive the sockets starting with FD 3, the number of + passed FDs in `$LISTEN_FDS` and its PID as `$LISTEN_PID`. It should take + these and pass them on to the container's init process, also setting + $LISTEN_FDS and `$LISTEN_PID` (basically, it can just leave the FDs and + `$LISTEN_FDS` untouched, but it needs to adjust `$LISTEN_PID` to the + container init process). That's all that's necessary to make socket + activation work. The protocol to hand sockets from systemd to services is + hence the same as from the container manager to the container systemd. For + further details see the explanations of + [sd_listen_fds(1)](http://0pointer.de/public/systemd-man/sd_listen_fds.html) + and the [blog story for service + developers](http://0pointer.de/blog/projects/socket-activation.html). + +5. Container managers should stay away from the cgroup hierarchy outside of the + unit they created for their container. That's private property of systemd, + and no other code should modify it. + +## Networking + +1. Inside of a container, if a `veth` link is named `host0`, `systemd-networkd` + running inside of the container will by default run DHCPv4, DHCPv6, and + IPv4LL clients on it. It is thus recommended that container managers that + add a `veth` link to a container name it `host0`, to get an automatically + configured network, with no manual setup. + +2. Outside of a container, if a `veth` link is prefixed "ve-", `systemd-networkd` + will by default run DHCPv4 and DHCPv6 servers on it, as well as IPv4LL. It + is thus recommended that container managers that add a `veth` link to a + container name the external side `ve-` + the container name. + +3. It is recommended to configure stable MAC addresses for container `veth` + devices, for example hashed out of the container names. That way it is more + likely that DHCP and IPv4LL will acquire stable addresses. + +## What You Shouldn't Do + +1. Do not drop `CAP_MKNOD` from the container. `PrivateDevices=` is a commonly + used service setting that provides a service with its own, private, minimal + version of `/dev/`. To set this up systemd in the container needs this + capability. If you take away the capability than all services that set this + flag will cease to work. Use `BPF_PROG_TYPE_CGROUP_DEVICE` BPF programs — on + cgroupv2 — or the `devices` controller — on cgroupv1 — to restrict what + device nodes the container can create instead of taking away the capability + wholesale. (Also see the section about fully unprivileged containers below.) + +2. Do not drop `CAP_SYS_ADMIN` from the container. A number of the most + commonly used file system namespacing related settings, such as + `PrivateDevices=`, `ProtectHome=`, `ProtectSystem=`, `MountFlags=`, + `PrivateTmp=`, `ReadWriteDirectories=`, `ReadOnlyDirectories=`, + `InaccessibleDirectories=`, and `MountFlags=` need to be able to open new + mount namespaces and the mount certain file systems into them. You break all + services that make use of these options if you drop the capability. Also + note that logind mounts `XDG_RUNTIME_DIR` as `tmpfs` for all logged in users + and that won't work either if you take away the capability. (Also see + section about fully unprivileged containers below.) + +3. Do not cross-link `/dev/kmsg` with `/dev/console`. They are different things, + you cannot link them to each other. + +4. Do not pretend that the real VTs are available in the container. The VT + subsystem consists of all the devices `/dev/tty*`, `/dev/vcs*`, `/dev/vcsa*` + plus their `sysfs` counterparts. They speak specific `ioctl()`s and + understand specific escape sequences, that other ptys don't understand. + Hence, it is explicitly not OK to mount a pty to `/dev/tty1`, `/dev/tty2`, + `/dev/tty3`. This is explicitly not supported. + +5. Don't pretend that passing arbitrary devices to containers could really work + well. For example, do not pass device nodes for block devices to the + container. Device access (with the exception of network devices) is not + virtualized on Linux. Enumeration and probing of meta information from + `/sys/` and elsewhere is not possible to do correctly in a container. Simply + adding a specific device node to a container's `/dev/` is *not* *enough* to + do the job, as `systemd-udevd` and suchlike are not available at all, and no + devices will appear available or enumerable, inside the container. + +6. Don't mount only a sub-tree of the `cgroupfs` into the container. This will not + work as `/proc/$PID/cgroup` lists full paths and cannot be matched up with + the actual `cgroupfs` tree visible, then. (You may "prune" some branches + though, see above.) + +7. Do not make `/sys/` writable in the container. If you do, + `systemd-udevd.service` is started to manage your devices — inside the + container, but that will cause conflicts and errors given that the Linux + device model is not virtualized for containers on Linux and thus the + containers and the host would try to manage the same devices, fighting for + ownership. Multiple other subsystems of systemd similarly test for `/sys/` + being writable to decide whether to use `systemd-udevd` or assume that + device management is properly available on the instance. Among them + `systemd-networkd` and `systemd-logind`. The conditionalization on the + read-only state of `/sys/` enables a nice automatism: as soon as `/sys/` and + the Linux device model are changed to be virtualized properly the container + payload can make use of that, simply by marking `/sys/` writable. (Note that + as special exception, the devices in `/sys/class/net/` are virtualized + already, if network namespacing is used. Thus it is OK to mount the relevant + sub-directories of `/sys/` writable, but make sure to leave the root of + `/sys/` read-only.) + +## Fully Unprivileged Container Payload + +First things first, to make this clear: Linux containers are not a security +technology right now. There are more holes in the model than in swiss cheese. + +For example: if you do not use user namespacing, and share root and other users +between container and host, the `struct user` structures will be shared between +host and container, and hence `RLIMIT_NPROC` and so of the container users +affect the host and other containers, and vice versa. This is a major security +hole, and actually is a real-life problem: since Avahi sets `RLIMIT_NPROC` of +its user to 2 (to effectively disallow `fork()`ing) you cannot run more than +one Avahi instance on the entire system... + +People have been asking to be able to run systemd without `CAP_SYS_ADMIN` and +`CAP_SYS_MKNOD` in the container. This is now supported to some level in +systemd, but we recommend against it (see above). If `CAP_SYS_ADMIN` and +`CAP_SYS_MKNOD` are missing from the container systemd will now gracefully turn +off `PrivateTmp=`, `PrivateNetwork=`, `ProtectHome=`, `ProtectSystem=` and +others, because those capabilities are required to implement these options. The +services using these settings (which include many of systemd's own) will hence +run in a different, less secure environment when the capabilities are missing +than with them around. + +With user namespacing in place things get much better. With user namespaces the +`struct user` issue described above goes away, and containers can keep +`CAP_SYS_ADMIN` safely for the user namespace, as capabilities are virtualized +and having capabilities inside a container doesn't mean one also has them +outside. + +## Final Words + +If you write software that wants to detect whether it is run in a container, +please check `/proc/1/environ` and look for the `container=` environment +variable. Do not assume the environment variable is inherited down the process +tree. It generally is not. Hence check the environment block of PID 1, not your +own. Note though that that file is only accessible to root. systemd hence early +on also copies the value into `/run/systemd/container`, which is readable for +everybody. However, that's a systemd-specific interface and other init systems +are unlikely to do the same. + +Note that it is our intention to make systemd systems work flawlessly and +out-of-the-box in containers. In fact we are interested to ensure that the same +OS image can be booted on a bare system, in a VM and in a container, and behave +correctly each time. If you notice that some component in systemd does not work +in a container as it should, even though the container manager implements +everything documented above, please contact us. diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 565acdd1c..0ee71b274 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,5 +1,7 @@ --- title: Contributing +category: Contributing +layout: default --- # Contributing diff --git a/docs/DISCOVERABLE_PARTITIONS.md b/docs/DISCOVERABLE_PARTITIONS.md new file mode 100644 index 000000000..f1537b893 --- /dev/null +++ b/docs/DISCOVERABLE_PARTITIONS.md @@ -0,0 +1,216 @@ +--- +title: Discoverable Partitions Specification +category: Concepts +layout: default +--- +# The Discoverable Partitions Specification + +_TL;DR: Let's automatically discover, mount and enable the root partition, +`/home/`, `/srv/`, `/var/` and `/var/tmp/` and the swap partitions based on +GUID Partition Tables (GPT)!_ + +The GUID Partition Table (GPT) is mandatory on EFI systems. It allows +identification of partition types with UUIDs. So far Linux has made little use +of this, and mostly just defined one UUID for file system/data partitions and +another one for swap partitions. With this specification, we introduce +additional partition types to enable automatic discovery of partitions and +their intended mountpoint. This has many benefits: + +* OS installers can automatically discover and make sense of partitions of + existing Linux installations. +* The OS can discover and mount the necessary file systems with a non-existing + or incomplete `/etc/fstab` file and without the `root=` kernel command line + option. +* Container managers (such as nspawn and libvirt-lxc) can decode and set up + file systems contained in GPT disk images automatically and mount them to the + right places, thus allowing booting the same, identical images on bare-metal + and in Linux containers. This enables true, natural portability of disk + images between physical machines and Linux containers. +* As a help to administrators and users partition manager tools can show more + descriptive information about partitions tables. + +Note that the OS side of this specification is currently implemented in +[systemd](http://systemd.io/) 211 and newer in the +[systemd-auto-gpt-generator(8)](http://www.freedesktop.org/software/systemd/man/systemd-gpt-auto-generator.html) +generator tool. Note that automatic discovery of the root only works if the +boot loader communicates this information to the OS, by implementing the [Boot +Loader +Interface](https://systemd.io/BOOT_LOADER_INTERFACE). + +## Defined Partition Type UUIDs + +| Partition Type UUID | Name | Allowed File Systems | Explanation | +|---------------------|------|----------------------|-------------| +| `44479540-f297-41b2-9af7-d131d5f0458a` | _Root Partition (x86)_ | Any native, optionally in LUKS | On systems with matching architecture, the first partition with this type UUID on the disk containing the active EFI ESP is automatically mounted to the root directory /. If the partition is encrypted with LUKS or has dm-verity integrity data (see below), the device mapper file will be named `/dev/mapper/root`. | +| `4f68bce3-e8cd-4db1-96e7-fbcaf984b709` | _Root Partition (x86-64)_ | ditto | ditto | +| `69dad710-2ce4-4e3c-b16c-21a1d49abed3` | _Root Partition (32-bit ARM)_ | ditto | ditto | +| `b921b045-1df0-41c3-af44-4c6f280d3fae` | _Root Partition (64-bit ARM/AArch64)_ | ditto | ditto | +| `993d8d3d-f80e-4225-855a-9daf8ed7ea97` | _Root Partition (Itanium/IA-64)_ | ditto | ditto | +| `d13c5d3b-b5d1-422a-b29f-9454fdc89d76` | _Root Verity Partition (x86)_ | A dm-verity superblock followed by hash data | On systems with matching architecture, contains dm-verity integrity hash data for the matching root partition. If this feature is used the partition UUID of the root partition should be the first 128bit of the root hash of the dm-verity hash data, and the partition UUID of this dm-verity partition should be the final 128bit of it, so that the root partition and its verity partition can be discovered easily, simply by specifying the root hash. | +| `2c7357ed-ebd2-46d9-aec1-23d437ec2bf5` | _Root Verity Partition (x86-64)_ | ditto | ditto | +| `7386cdf2-203c-47a9-a498-f2ecce45a2d6` | _Root Verity Partition (32-bit ARM)_ | ditto | ditto | +| `df3300ce-d69f-4c92-978c-9bfb0f38d820` | _Root Verity Partition (64-bit ARM/AArch64)_ | ditto | ditto | +| `86ed10d5-b607-45bb-8957-d350f23d0571` | _Root Verity Partition (Itanium/IA-64)_ | ditto | ditto | +| `933ac7e1-2eb4-4f13-b844-0e14e2aef915` | _Home Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/home/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/home`. | +| `3b8f8425-20e0-4f3b-907f-1a25a76f98e8` | _Server Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/srv/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/srv`. | +| `4d21b016-b534-45c2-a9fb-5c16e091fd2d` | _Variable Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/var/` — under the condition that its partition UUID matches the first 128 bit of `HMAC-SHA256(machine-id, 0x4d21b016b53445c2a9fb5c16e091fd2d)` (i.e. the SHA256 HMAC hash of the binary type UUID keyed by the machine ID as read from [`/etc/machine-id`](https://www.freedesktop.org/software/systemd/man/machine-id.html). This special requirement is made because `/var/` (unlike the other partition types listed here) is inherently private to a specific installation and cannot possibly be shared between multiple OS installations on the same disk, and thus should be bound to a specific instance of the OS, identified by its machine ID. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/var`. | +| `7ec6f557-3bc5-4aca-b293-16ef5df639d1` | _Temporary Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/var/tmp/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/tmp`. Note that the intended mount point is indeed `/var/tmp/`, not `/tmp/`. The latter is typically maintained in memory via tmpfs and does not require a partition on disk. In some cases it might be desirable to make `/tmp/` persistent too, in which case it is recommended to make it a symlink or bind mount to `/var/tmp/`, thus not requiring its own partition type UUID. | +| `0657fd6d-a4ab-43c4-84e5-0933c84b4f4f` | _Swap_ | Swap | All swap partitions on the disk containing the root partition are automatically enabled. | +| `c12a7328-f81f-11d2-ba4b-00a0c93ec93b` | _EFI System Partition_ | VFAT | The ESP used for the current boot is automatically mounted to `/efi/` (or `/boot/` as fallback), unless a different partition is mounted there (possibly via `/etc/fstab`, or because the Extended Boot Loader Partition — see below — exists) or the directory is non-empty on the root disk. This partition type is defined by the [UEFI Specification](http://www.uefi.org/specifications). | +| `bc13c2ff-59e6-4262-a352-b275fd6f7172` | _Extended Boot Loader Partition_ | Typically VFAT | The Extended Boot Loader Partition (XBOOTLDR) used for the current boot is automatically mounted to /boot/, unless a different partition is mounted there (possibly via /etc/fstab) or the directory is non-empty on the root disk. This partition type is defined by the [Boot Loader Specification](https://systemd.io/BOOT_LOADER_SPECIFICATION). | +| `0fc63daf-8483-4772-8e79-3d69d8477de4` | _Other Data Partitions_ | Any native, optionally in LUKS | No automatic mounting takes place for other Linux data partitions. This partition type should be used for all partitions that carry Linux file systems. The installer needs to mount them explicitly via entries in /etc/fstab. Optionally, these partitions may be encrypted with LUKS. | + +Other GPT type IDs might be used on Linux, for example to mark software RAID or +LVM partitions. The definitions of those GPT types is outside of the scope of +this specification. + +[systemd-id128(1)](http://www.freedesktop.org/software/systemd/man/systemd-i128.html) +may be used to list those UUIDs. + +## Partition Names + +For partitions of the types listed above it is recommended to use +human-friendly, descriptive partition names in the GPT partition table, for +example "*Home*", "*Server* *Data*", "*Fedora* *Root*" and similar, possibly +localized. + +## Partition Flags + +For the root, server data, home, variable data, temporary data and swap +partitions, the partition flag bit 63 ("*no-auto*") may be used to turn off +auto-discovery for the specific partition. If set, the partition will not be +automatically mounted or enabled. + +For the root, server data, home, variable data and temporary data partitions, +the partition flag bit 60 ("*read-only*") may be used to mark a partition for +read-only mounts only. If set, the partition will be mounted read-only instead +of read-write. Note that the variable data partition and the temporary data +partition will generally not be able to serve their purpose if marked +read-only, since by their very definition they are supposed to be mutable. (The +home and server data partitions are generally assumed to be mutable as well, +but the requirement for them is not equally strong.) Because of that, while the +read-only flag is defined and supported, it's almost never a good idea to +actually use it for these partitions. + +Note that these two flag definitions happen to map nicely to the ones used by +Microsoft Basic Data Partitions. + +## Suggested Mode of Operation + +An *installer* that repartitions the hard disk _should_ use the above UUID +partition types for appropriate partitions it creates. + +An *installer* which supports a "manual partitioning" interface _may_ choose to +pre-populate the interface with swap, `/home/`, `/srv/`, `/var/tmp/` partitions +of pre-existing Linux installations, identified with the GPT type UUIDs +above. The installer should not pre-populate such an interface with any +identified root or `/var/` partition unless the intention is to overwrite an +existing operating system that might be installed. + +An *installer* _may_ omit creating entries in `/etc/fstab` for root, `/home/`, +`/srv/`, `/var/`, `/var/tmp` and for the swap partitions if they use these UUID +partition types, and are the first partitions on the disk of each type. If the +ESP shall be mounted to `/efi/` (or `/boot/`), it may additionally omit +creating the entry for it in `/etc/fstab`. If an extended boot partition is +used, or if the EFI partition shall not be mounted to `/efi/` or `/boot/`, it +_must_ create `/etc/fstab` entries for them. If other partitions are used (for +example for `/usr/` or `/var/lib/mysql/`), the installer _must_ register these +in `/etc/fstab`. The `root=` parameter passed to the kernel by the boot loader +may be omitted if the root partition is the first one on the disk of its type. +If the root partition is not the first one on the disk, the `root=` parameter +_must_ be passed to the kernel by the boot loader. An installer that mounts a +root, `/home/`, `/srv/`, `/var/`, or `/var/tmp/` file system with the partition +types defined as above which contains a LUKS header _must_ call the device +mapper device "root", "home", "srv", "var" or "tmp", respectively. This is +necessary to ensure that the automatic discovery will never result in different +device mapper names than any static configuration by the installer, thus +eliminating possible naming conflicts and ambiguities. + +An *operating* *system* _should_ automatically discover and mount the first +root partition that does not have the no-auto flag set (as described above) by +scanning the disk containing the currently used EFI ESP. It _should_ +automatically discover and mount the first `/home/`, `/srv/`, `/var/`, +`/var/tmp/` and swap partitions that do not have the no-auto flag set by +scanning the disk containing the discovered root partition. It should +automatically discover and mount the partition containing the currently used +EFI ESP to `/efi/` (or `/boot/` as fallback). It should automatically discover +and mount the partition containing the currently used Extended Boot Loader +Partition to `/boot/`. It _should not_ discover or automatically mount +partitions with other UUID partition types, or partitions located on other +disks, or partitions with the no-auto flag set. User configuration shall +always override automatic discovery and mounting. If a root, `/home/`, +`/srv/`, `/boot/`, `/var/`, `/var/tmp/`, `/efi/`, `/boot/` or swap partition is +listed in `/etc/fstab` or with `root=` on the kernel command line, it _must_ +take precedence over automatically discovered partitions. If a `/home/`, +`/srv/`, `/boot/`, `/var/`, `/var/tmp/`, `/efi/` or `/boot/` directory is found +to be populated already in the root partition, the automatic discovery _must +not_ mount any discovered file system over it. + +A *container* *manager* should automatically discover and mount the root, +`/home/`, `/srv/`, `/var/`, `/var/tmp/` partitions inside a container disk +image. It may choose to mount any discovered ESP and/or XBOOOTLDR partition to +`/efi/` or `/boot/`. It should ignore any swap should they be included in a +container disk image. + +If a btrfs file system is automatically discovered and mounted by the operating +system/container manager it will be mounted with its *default* subvolume. The +installer should make sure to set the default subvolume correctly using "btrfs +subvolume set-default". + +## Sharing of File Systems between Installations + +If two Linux-based operating systems are installed on the same disk, the scheme +above suggests that they may share the swap, `/home/`, `/srv/`, `/var/tmp/`, +ESP, XBOOTLDR. However, they should each have their own root and `/var/` +partition. + +## Frequently Asked Questions + +### Why are you taking my `/etc/fstab` away? + +We are not. `/etc/fstab` always overrides automatic discovery and is indeed +mentioned in the specifications. We are simply trying to make the boot and +installation processes of Linux a bit more robust and self-descriptive. + +### Why did you only define the root partition for x86, x86-64, ARM, ARM64, ia64? + +The automatic discovery of the root partition is defined to operate on the disk +containing the current EFI System Partition (ESP). Since EFI only exists on +x86, x86-64, ia64, and ARM so far, we only defined root partition UUIDs for +these architectures. Should EFI become more common on other architectures, we +can define additional UUIDs for them. + +### Why define distinct root partition UUIDs for the various architectures? + +This allows disk images that may be booted on multiple architectures to use +discovery of the appropriate root partition on each architecture. + +### Doesn't this break multi-boot scenarios? + +No, it doesn't. The specification says that installers may not stop creating +`/etc/fstab` or stop including `root=` on the kernel command line, unless the used +partitions are the first ones of their type on the disk. Additionally, +`/etc/fstab` and `root=` both override automatic discovery. Multi-boot is hence +well supported, since it doesn't change anything for anything but the first +installation. + +That all said, it's not expected that generic installers generally stop setting +`root=` and creating `/etc/fstab` anyway. The option to drop these configuration +bits is primarily something for appliance-like devices. However, generic +installers should *still* set the right GPT partition types for the partitions +they create so that container managers, partition tools and administrators can +benefit. Phrased differently, this specification introduces A) the +*recommendation* to use the newly defined partition types to tag things +properly and B) the *option* to then drop `root=` and `/etc/fstab`. While we +advertise A) to *all* installers, we only propose B) for simpler, +appliance-like installations. + +### What partitioning tools will create a DPS-compliant partition table? + +As of util-linux 2.25.2, the fdisk tool provides type codes to create the root, +home, and swap partitions that the DPS expects, but the gdisk tool (version +0.8.10) and its variants do not support creation of a root file system with a +matching type code. By default, fdisk will create an old-style MBR, not a GPT, +so typing 'l' to list partition types will not show the choices that the root +partition with the correct UUID. You must first create an empty GPT and then +type 'l' in order for the DPS-compliant type codes to be available. diff --git a/docs/DISTRO_PORTING.md b/docs/DISTRO_PORTING.md index d14bf131b..2e4782f40 100644 --- a/docs/DISTRO_PORTING.md +++ b/docs/DISTRO_PORTING.md @@ -1,5 +1,7 @@ --- title: Porting systemd To New Distributions +category: Concepts +layout: default --- # Porting systemd To New Distributions diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index a3837ebfd..fec40b1e9 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -1,5 +1,7 @@ --- title: Known Environment Variables +category: Interfaces +layout: default --- # Known Environment Variables @@ -71,6 +73,13 @@ All tools: appropriate path under /run. This variable is also set by the manager when RuntimeDirectory= is used, see systemd.exec(5). +* `$SYSTEMD_CRYPT_PREFIX` — if set configures the hash method prefix to use for + UNIX crypt() when generating passwords. By default the system's "preferred + method" is used, but this can be overridden with this environment + variable. Takes a prefix such as `$6$` or `$y$`. (Note that this is only + honoured on systems built with libxcrypt and is ignored on systems using + glibc's original, internal crypt() implementation.) + systemctl: * `$SYSTEMCTL_FORCE_BUS=1` — if set, do not connect to PID1's private D-Bus diff --git a/docs/GROUP_RECORD.md b/docs/GROUP_RECORD.md new file mode 100644 index 000000000..8f98b49c2 --- /dev/null +++ b/docs/GROUP_RECORD.md @@ -0,0 +1,158 @@ +--- +title: JSON Group Records +category: Interfaces +layout: default +--- + +# JSON Group Records + +Long story short: JSON Group Records are to `struct group` what [JSON User +Records](https://systemd.io/USER_RECORD.md) are to `struct passwd`. + +Conceptually, much of what applies to JSON user records also applies to JSON +group records. They also consist of seven sections, with similar properties and +they carry some identical (or at least very similar) fields. + +## Fields in the `regular` section + +`groupName` → A string with the UNIX group name. Matches the `gr_name` field of +UNIX/glibc NSS `struct group`, or the shadow structure `struct sgrp`'s +`sg_namp` field. + +`realm` → The "realm" the group belongs to, conceptually identical to the same +field of user records. A string in DNS domain name syntax. + +`disposition` → The disposition of the group, conceptually identical to the +same field of user records. A string. + +`service` → A string, an identifier for the service managing this group record +(this field is typically in reverse domain name syntax.) + +`lastChangeUSec` → An unsigned 64bit integer, a timestamp (in µs since the UNIX +epoch 1970) of the last time the group record has been modified. (Covers only +the `regular`, `perMachine` and `privileged` sections). + +`gid` → An unsigned integer in the range 0…4294967295: the numeric UNIX group +ID (GID) to use for the group. This corresponds to the `gr_gid` field of +`struct group`. + +`members` → An array of strings, listing user names that are members of this +group. Note that JSON user records also contain a `memberOf` field, or in other +words a group membership can either be denoted in the JSON user record or in +the JSON group record, or in both. The list of memberships should be determined +as the combination of both lists (plus optionally others). If a user is listed +as member of a group and doesn't exist it should be ignored. This field +corresponds to the `gr_mem` field of `struct group` and the `sg_mem` field of +`struct sgrp`. + +`administrators` → Similarly, an array of strings, listing user names that +shall be considered "administrators" of this group. This field corresponds to +the `sg_adm` field of `struct sgrp`. + +`privileged`/`perMachine`/`binding`/`status`/`signature`/`secret` → The +objects/arrays for the other six group record sections. These are organized the +same way as for the JSON user records, and have the same semantics. + +## Fields in the `privileged` section + +The following fields are defined: + +`hashedPassword` → An array of strings with UNIX hashed passwords; see the +matching field for user records for details. This field corresponds to the +`sg_passwd` field of `struct sgrp` (and `gr_passwd` of `struct group` in a +way). + +## Fields in the `perMachine` section + +`matchMachineId`/`matchHostname` → Strings, match expressions similar as for +user records, see the user record documentation for details. + +The following fields are defined for the `perMachine` section and are defined +equivalent to the fields of the same name in the `regular` section, and +override those: + +`gid`, `members`, `administrators` + +## Fields in the `binding` section + +The following fields are defined for the `binding` section, and are equivalent +to the fields of the same name in the `regular` and `perMachine` sections: + +`gid` + +## Fields in the `status` section + +The following fields are defined in the `status` section, and are mostly +equivalent to the fields of the same name in the `regular` section, though with +slightly different conceptual semantics, see the same fields in the user record +documentation: + +`service` + +## Fields in the `signature` section + +The fields in this section are defined identically to those in the matching +section in the user record. + +## Fields in the `secret` section + +Currently no fields are defined in this section for group records. + +## Mapping to `struct group` and `struct sgrp` + +When mapping classic UNIX group records (i.e. `struct group` and `struct sgrp`) +to JSON group records the following mappings should be applied: + +| Structure | Field | Section | Field | Condition | +|----------------|-------------|--------------|------------------|----------------------------| +| `struct group` | `gr_name` | `regular` | `groupName` | | +| `struct group` | `gr_passwd` | `privileged` | `password` | (See notes below) | +| `struct group` | `gr_gid` | `regular` | `gid` | | +| `struct group` | `gr_mem` | `regular` | `members` | | +| `struct sgrp` | `sg_namp` | `regular` | `groupName` | | +| `struct sgrp` | `sg_passwd` | `privileged` | `password` | (See notes below) | +| `struct sgrp` | `sg_adm` | `regular` | `administrators` | | +| `struct sgrp` | `sg_mem` | `regular` | `members` | | + +At this time almost all Linux machines employ shadow passwords, thus the +`gr_passwd` field in `struct group` is set to `"x"`, and the actual password +is stored in the shadow entry `struct sgrp`'s field `sg_passwd`. + +## Extending These Records + +The same logic and recommendations apply as for JSON user records. + +## Examples + +A reasonable group record for a system group might look like this: + +```json +{ + "groupName" : "systemd-resolve", + "gid" : 193, + "status" : { + "6b18704270e94aa896b003b4340978f1" : { + "service" : "io.systemd.NameServiceSwitch" + } + } +} +``` + +And here's a more complete one for a regular group: + +```json +{ + "groupName" : "grobie", + "binding" : { + "6b18704270e94aa896b003b4340978f1" : { + "gid" : 60232 + } + }, + "disposition" : "regular", + "status" : { + "6b18704270e94aa896b003b4340978f1" : { + "service" : "io.systemd.Home" + } + } +} +``` diff --git a/docs/HACKING.md b/docs/HACKING.md index 7dc1eb98c..c0516b5c6 100644 --- a/docs/HACKING.md +++ b/docs/HACKING.md @@ -1,5 +1,7 @@ --- title: Hacking on systemd +category: Contributing +layout: default --- # Hacking on systemd @@ -125,7 +127,5 @@ guidance in [CONTRIBUTING.md](CONTRIBUTING.md) on how to report a security vulne For more details on building fuzzers and integrating with OSS-Fuzz, visit: -- https://github.com/google/oss-fuzz/blob/master/docs/new_project_guide.md -- https://llvm.org/docs/LibFuzzer.html -- https://github.com/google/fuzzer-test-suite/blob/master/tutorial/libFuzzerTutorial.md -- https://chromium.googlesource.com/chromium/src/testing/libfuzzer/+/HEAD/efficient_fuzzer.md +- [Setting up a new project - OSS-Fuzz](https://google.github.io/oss-fuzz/getting-started/new-project-guide/) +- [Tutorials - OSS-Fuzz](https://google.github.io/oss-fuzz/reference/useful-links/#tutorials) diff --git a/docs/HOME_DIRECTORY.md b/docs/HOME_DIRECTORY.md new file mode 100644 index 000000000..73c2359ff --- /dev/null +++ b/docs/HOME_DIRECTORY.md @@ -0,0 +1,173 @@ +--- +title: Home Directories +category: Concepts +layout: default +--- + +# Home Directories + +[`systemd-homed.service(8)`](https://www.freedesktop.org/software/systemd/man/systemd-homed.service.html) +manages home directories of regular ("human") users. Each directory it manages +encapsulates both the data store and the user record of the user so that it +comprehensively describes the user account, and is thus naturally portable +between systems without any further, external metadata. This document describes +the format used by these home directories, in context of the storage mechanism +used. + +## General Structure + +Inside of the home directory a file `~/.identity` contains the JSON formatted +user record of the user. It follows the format defined in [`JSON User +Records`](https://systemd.io/USER_RECORD). It is recommended to bring the +record into 'normalized' form (i.e. all objects should contain their fields +sorted alphabetically by their key) before storing it there, though this is not +required nor enforced. Since the user record is cryptographically signed the +user cannot make modifications to the file on their own (at least not without +corrupting it, or knowing the private key used for signing the record). Note +that user records are stored here without their `binding`, `status` and +`secret` sections, i.e. only with the sections included in the signature plus +the signature section itself. + +## Storage Mechanism: Plain Directory/`btrfs` Subvolume + +If the plain directory or `btrfs` subvolume storage mechanism of +`systemd-homed` is used (i.e. `--storage=directory` or `--storage=subvolume` on +the +[`homectl(1)`](https://www.freedesktop.org/software/systemd/man/homectl.html) +command line) the home directory requires no special set-up besides including +the user record in the `~/.identity` file. + +It is recommended to name home directories managed this way by +`systemd-homed.service` by the user name, suffixed with `.homedir` (example: +`lennart.homedir` for a user `lennart`) but this is not enforced. When the user +is logged in the directory is generally mounted to `/home/$USER` (in our +example: `/home/lennart`), thus dropping the suffix while the home directory is +active. `systemd-homed` will automatically discover home directories named this +way in `/home/*.homedir` and synthesize NSS user records for them as they show +up. + +## Storage Mechanism: `fscrypt` Directories + +This storage mechanism is mostly identical to the plain directory storage +mechanism, except that the home directory is encrypted using `fscrypt`. (Use +`--storage=fscrypt` on the `homectl` command line.) Key management is +implemented via extended attributes on the directory itself: for each password +an extended attribute `trusted.fscrypt_slot0`, `trusted.fscrypt_slot1`, +`trusted.fscrypt_slot2`, … is maintained. It's value contains a colon-separated +pair of Base64 encoded data fields. The first field contains a salt value, the +second field the encrypted volume key. The latter is encrypted using AES256 in +counter mode, using a key derived from the password via PBKDF2-HMAC-SHA512 +together with the salt value. The construction is similar to what LUKS does for +`dm-crypt` encrypted volumes. Note that extended attributes are not encrypted +by `fscrypt` and hence are suitable for carry the key slots. Moreover, by using +extended attributes the slots are directly attached to the directory and an +independent sidecar key database is not required. + +## Storage Mechanism: `cifs` Home Directories + +In this storage mechanism the home directory is mounted from a CIFS server and +service at login, configured inside the user record. (Use `--storage=cifs` on +the `homectl` command line.) The local password of the user is used to log into +the CIFS service. The directory share needs to contain the user record in +`~/.identity` as well. Note that this means that the user record needs to be +registered locally before it can be mounted for the first time, since CIFS +domain and server information needs to be known *before* the mount. Note that +for all other storage mechanisms it is entirely sufficient if the directories +or storage artifacts are placed at the right locations — all information to +activate them can be derived automatically from their mere availability. + +## Storage Mechanism: `luks` Home Directories + +This is the most advanced and most secure storage mechanism and consists of a +Linux file system inside a LUKS2 volume inside a loopback file (or on removable +media). (Use `--storage=luks` on the `homectl` command line.) Specifically: + +* The image contains a GPT partition table. For now it should only contain a + single partition, and that partition must have the type UUID + `773f91ef-66d4-49b5-bd83-d683bf40ad16`. It's partition label must be the + user name. + +* This partition must contain a LUKS2 volume, whose label must be the user + name. The LUKS2 volume must contain a LUKS2 token field of type + `systemd-homed`. The JSON data of this token must have a `record` field, + containing a string with base64-encoded data. This data is the JSON user + record, in the same serialization as in `~/.identity`, though encrypted. The + JSON data of this token must also have an `iv` field, which contains a + base64-encoded binary initialization vector for the encryption. The + encryption used is the same as the LUKS2 volume itself uses, unlocked by the + same volume key, but based on its own IV. + +* Inside of this LUKS2 volume must be a Linux file system, one of `ext4`, + `btrfs` and `xfs`. The file system label must be the user name. + +* This file system should contain a single directory named after the user. This + directory will become the home directory of the user when activated. It + contains a second copy of the user record in the `~/.identity` file, like in + the other storage mechanisms. + +The image file should either reside in a directory `/home/` on the system, +named after the user, suffixed with `.home`. When activated the container home +directory is mounted to the same path, though with the `.home` suffix dropped — +unless a different mount point is defined in the user record. (e.g.: the +loopback file `/home/waldo.home` is mounted to `/home/waldo` while activated.) +When the image is stored on removable media (such as a USB stick) the image +file can be directly `dd`'ed onto it, the format is unchanged. The GPT envelope +should ensure the image is properly recognizable as a home directory both when +used in a loopback file and on a removable USB stick. (Note that when mounting +a home directory from an USB stick it too defaults to a directory in `/home/`, +named after the username, with no further suffix.) + +Rationale for the GPT partition table envelope: this way the image is nicely +discoverable and recognizable already by partition managers as a home +directory. Moreover, when copied onto a USB stick the GPT envelope makes sure +the stick is properly recognizable as a portable home directory +medium. (Moreover it allows to embed additional partitions later on, for +example for allowing a multi-purpose USB stick that contains both a home +directory and a generic storage volume.) + +Rationale for including the encrypted user record in the the LUKS2 header: +Linux kernel file system implementations are generally not robust towards +maliciously formatted file systems; there's a good chance that file system +images can be used as attack vectors, exploiting the kernel. Thus it is +necessary to validate the home directory image *before* mounting it and +establishing a minimal level of trust. Since the user record data is +cryptographically signed and user records not signed with a recognized private +key are not accepted a minimal level of trust between the system and the home +directory image is established. + +Rationale for storing the home directory one level below to root directory of +the contained file system: this way special directories such as `lost+found/` +do not show up in the user's home directory. + +## Algorithm + +Regardless of the storage mechanism used, an activated home directory +necessarily involves a mount point to be established. In case of the +directory-based storage mechanisms (`directory`, `subvolume` and `fscrypt`) +this is a bind mount, in case of `cifs` this is a CIFS network mount, and in +case of the LUKS2 backend a regular block device mount of the file system +contained in the LUKS2 image. By requiring a mount for all cases (even for +those that already are a directory) a clear logic is defined to distuingish +active and inactive home directories, so that the directories become +inaccessible under their regular path the instant they are +deactivated. Moreover, the `nosuid`, `nodev` and `noexec` flags configured in +the user record are applied when the bind mount is established. + +During activation, the user records retained on the host, the user record +stored in the LUKS2 header (in case of the LUKS2 storage mechanism) and the +user record stored inside the home directory in `~/.identity` are +compared. Activation is only permitted if they match the same user and are +signed by a recognized key. When the three instances differ in `lastChangeUSec` +field, the newest record wins, and is propagated to the other two locations. + +During activation the file system checker (`fsck`) appropriate for the +selected file system is automatically invoked, ensuring the file system is in a +healthy state before it is mounted. + +If the UID assigned to a user does not match the owner of the home directory in +the file system, the home directory is automatically and recursively `chown()`ed +to the correct UID. + +Depending on the `discard` setting of the user record either the backing +loopback file is `fallocate()`ed during activation, or the mounted file system +is `FITRIM`ed after mounting, to ensure the setting is correctly enforced. diff --git a/docs/INITRD_INTERFACE.md b/docs/INITRD_INTERFACE.md new file mode 100644 index 000000000..8985f2761 --- /dev/null +++ b/docs/INITRD_INTERFACE.md @@ -0,0 +1,73 @@ +--- +title: Initrd Interface +category: Interfaces +layout: default +--- + + +# The initrd Interface of systemd + +The Linux initrd mechanism (short for "initial RAM disk") refers to a small +file system archive that is unpacked by the kernel and contains the first +userspace code that runs. It typically finds and transitions into the actual +root file system to use. systemd supports both initrd and initrd-less boots. If +an initrd is used it is a good idea to pass a few bits of runtime information +from the initrd to systemd in order to avoid duplicate work and to provide +performance data to the administrator. In this page we attempt to roughly +describe the interfaces that exist between the initrd and systemd. These +interfaces are currently used by dracut and the ArchLinux initrds. + +* The initrd should mount `/run/` as a tmpfs and pass it pre-mounted when + jumping into the main system when executing systemd. The mount options should + be `mode=755,nodev,nosuid,strictatime`. + +* It's highly recommended that the initrd also mounts `/usr/` (if split off) as + appropriate and passes it pre-mounted to the main system, to avoid the + problems described in [Booting without /usr is + Broken](http://freedesktop.org/wiki/Software/systemd/separate-usr-is-broken). + +* If the executable `/run/initramfs/shutdown` exists systemd will use it to + jump back into the initrd on shutdown. `/run/initramfs/` should be a usable + initrd environment to which systemd will pivot back and the `shutdown` + executable in it should be able to detach all complex storage that for + example was needed to mount the root file system. It's the job of the initrd + to set up this directory and executable in the right way so that this works + correctly. The shutdown binary is invoked with the shutdown verb as `argv[1]`, + optionally followed (in `argv[2]`, `argv[3]`, … systemd's original command + line options, for example `--log-level=` and similar. + +* Storage daemons run from the initrd should follow the the guide on [systemd + and Storage Daemons for the Root File + System](https://systemd.io/ROOT_STORAGE_DAEMONS) to survive properly from the + boot initrd all the way to the point where systemd jumps back into the initrd + for shutdown. + +One last clarification: we use the term _initrd_ very generically here +describing any kind of early boot file system, regardless whether that might be +implemented as an actual ramdisk, ramfs or tmpfs. We recommend using _initrd_ +in this sense as a term that is unrelated to the actual backing technologies +used. + +Oh, and one last question before closing: instead of implementing these +features in your own distro's initrd, may I suggest just using Dracut instead? +It's all already implemented there! + +## Using systemd inside an initrd + +It is also possible and recommended to implement the initrd itself based on +systemd. Here are a few terse notes: + +* Provide `/etc/initrd-release` in the initrd image. The idea is that it follows + the same format as the usual `/etc/os-release` but describes the initial RAM + disk implementation rather than the OS. systemd uses the existence of this + file as a flag whether to run in initial RAM disk mode, or not. + +* When run in initrd mode, systemd and its components will read a couple of + additional command line arguments, which are generally prefixed with `rd.` + +* To transition into the main system image invoke `systemctl switch-root`. + +* The switch-root operation will result in a killing spree of all running + processes. Some processes might need to be excluded from that, see the guide + on [systemd and Storage Daemons for the Root File + System](https://systemd.io/ROOT_STORAGE_DAEMONS). diff --git a/docs/PORTABILITY_AND_STABILITY.md b/docs/PORTABILITY_AND_STABILITY.md new file mode 100644 index 000000000..95bfcb98d --- /dev/null +++ b/docs/PORTABILITY_AND_STABILITY.md @@ -0,0 +1,162 @@ +--- +title: Interface Portability and Stability +category: Interfaces +layout: default +--- + +# Interface Portability and Stability Promise + +systemd provides various interfaces developers and programs might rely on. Starting with version 26 (the first version released with Fedora 15) we promise to keep a number of them stable and compatible for the future. + +The stable interfaces are: + +* **The unit configuration file format**. Unit files written now will stay compatible with future versions of systemd. Extensions to the file format will happen in a way that existing files remain compatible. + +* **The command line interface** of `systemd`, `systemctl`, `loginctl`, `journalctl`, and all other command line utilities installed in `$PATH` and documented in a man page. We will make sure that scripts invoking these commands will continue to work with future versions of systemd. Note however that the output generated by these commands is generally not included in the promise, unless it is documented in the man page. Example: the output of `systemctl status` is not stable, but that of `systemctl show` is, because the former is intended to be human readable and the latter computer readable, and this is documented in the man page. + +* **The protocol spoken on the socket referred to by `$NOTIFY_SOCKET`**, as documented in [sd_notify(3)](https://www.freedesktop.org/software/systemd/man/sd_notify.html). + +* Some of the **"special" unit names** and their semantics. To be precise the ones that are necessary for normal services, and not those required only for early boot and late shutdown, with very few exceptions. To list them here: `basic.target`, `shutdown.target`, `sockets.target`, `network.target`, `getty.target`, `graphical.target`, `multi-user.target`, `rescue.target`, `emergency.target`, `poweroff.target`, `reboot.target`, `halt.target`, `runlevel[1-5].target`. + +* **The D-Bus interfaces of the main service daemon and other daemons**. We try to always preserve backwards compatibility, and intentional breakage is never introduced. Nevertheless, when we find bugs that mean that the existing interface was not useful, or when the implementation did something different than stated by the documentation and the implemented behaviour is not useful, we will fix the implementation and thus introduce a change in behaviour. But the API (parameter counts and types) is never changed, and existing attributes and methods will not be removed. + +* For a more comprehensive and authoritative list, consult the chart below. + +The following interfaces will not necessarily be kept stable for now, but we will eventually make a stability promise for these interfaces too. In the meantime we will however try to keep breakage of these interfaces at a minimum: + +* **The set of states of the various state machines used in systemd**, e.g. the high-level unit states inactive, active, deactivating, and so on, as well (and in particular) the low-level per-unit states. + +* **All "special" units that aren't listed above**. + +The following interfaces are considered private to systemd, and are not and will not be covered by any stability promise: + +* **Undocumented switches** to `systemd`, `systemctl` and otherwise. + +* **The internal protocols** used on the various sockets such as the sockets `/run/systemd/shutdown`, `/run/systemd/private`. + +One of the main goals of systemd is to unify basic Linux configurations and service behaviors across all distributions. Systemd project does not contain any distribution-specific parts. Distributions are expected to convert over time their individual configurations to the systemd format, or they will need to carry and maintain patches in their package if they still decide to stay different. + +What does this mean for you? When developing with systemd, don't use any of the latter interfaces, or we will tell your mom, and she won't love you anymore. You are welcome to use the other interfaces listed here, but if you use any of the second kind (i.e. those where we don't yet make a stability promise), then make sure to subscribe to our mailing list, where we will announce API changes, and be prepared to update your program eventually. + +Note that this is a promise, not an eternal guarantee. These are our intentions, but if in the future there are very good reasons to change or get rid of an interface we have listed above as stable, then we might take the liberty to do so, despite this promise. However, if we do this, then we'll do our best to provide a smooth and reasonably long transition phase. + + +## Interface Portability And Stability Chart + +systemd provides a number of APIs to applications. Below you'll find a table detailing which APIs are considered stable and how portable they are. + +This list is intended to be useful for distribution and OS developers who are interested in maintaining a certain level of compatibility with the new interfaces systemd introduced, without relying on systemd itself. + +In general it is our intention to cooperate through interfaces and not code with other distributions and OSes. That means that the interfaces where this applies are best reimplemented in a compatible fashion on those other operating systems. To make this easy we provide detailed interface documentation where necessary. That said, it's all Open Source, hence you have the option to a) fork our code and maintain portable versions of the parts you are interested in independently for your OS, or b) build systemd for your distro, but leave out all components except the ones you are interested in and run them without the core of systemd involved. We will try not to make this any more difficult than necessary. Patches to allow systemd code to be more portable will be accepted on case-by-case basis (essentially, patches to follow well-established standards instead of e.g. glibc or linux extensions have a very high chance of being accepted, while patches which make the code ugly or exist solely to work around bugs in other projects have a low chance of being accepted). + +Many of these interfaces are already being used by applications and 3rd party code. If you are interested in compatibility with these applications, please consider supporting these interfaces in your distribution, where possible. + + +## General Portability of systemd and its Components + +**Portability to OSes:** systemd is not portable to non-Linux systems. It makes use of a large number of Linux-specific interfaces, including many that are used by its very core. We do not consider it feasible to port systemd to other Unixes (let alone non-Unix operating systems) and will not accept patches for systemd core implementing any such portability (but hey, it's git, so it's as easy as it can get to maintain your own fork...). APIs that are supposed to be used as library code are exempted from this: it is important to us that these compile nicely on non-Linux and even non-Unix platforms, even if they might just become NOPs. + +**Portability to Architectures:** It is important to us that systemd is portable to little endian as well as big endian systems. We will make sure to provide portability with all important architectures and hardware Linux runs on and are happy to accept patches for this. + +**Portability to Distributions:** It is important to us that systemd is portable to all Linux distributions. However, the goal is to unify many of the needless differences between the distributions, and hence will not accept patches for certain distribution-specific work-arounds. Compatibility with the distribution's legacy should be maintained in the distribution's packaging, and not in the systemd source tree. + +**Compatibility with Specific Versions of Other packages:** We generally avoid adding compatibility kludges to systemd that work around bugs in certain versions of other software systemd interfaces with. We strongly encourage fixing bugs where they are, and if that's not systemd we rather not try to fix it there. (There are very few exceptions to this rule possible, and you need an exceptionally strong case for it). + + +## General Portability of systemd's APIs + +systemd's APIs are available everywhere where systemd is available. Some of the APIs we have defined are supposed to be generic enough to be implementable independently of systemd, thus allowing compatibility with systems systemd itself is not compatible with, i.e. other OSes, and distributions that are unwilling to fully adopt systemd. + +A number of systemd's APIs expose Linux or systemd-specific features that cannot sensibly be implemented elsewhere. Please consult the table below for information about which ones these are. + +Note that not all of these interfaces are our invention (but most), we just adopted them in systemd to make them more prominently implemented. For example, we adopted many Debian facilities in systemd to push it into the other distributions as well. + + +--- + + +And now, here's the list of (hopefully) all APIs that we have introduced with systemd: + +| API | Type | Covered by Interface Stability Promise | Fully documented | Known External Consumers | Reimplementable Independently | Known Other Implementations | systemd Implementation portable to other OSes or non-systemd distributions | +| --- | ---- | ----------------------------------------------------------------------------------------- | ---------------- | ------------------------ | ----------------------------- | --------------------------- | -------------------------------------------------------------------------- | +| [hostnamed](https://www.freedesktop.org/wiki/Software/systemd/hostnamed) | D-Bus | yes | yes | GNOME | yes | [Ubuntu](https://launchpad.net/ubuntu/+source/ubuntu-system-service), [Gentoo](http://www.gentoo.org/proj/en/desktop/gnome/openrc-settingsd.xml), [BSD](http://uglyman.kremlin.cc/gitweb/gitweb.cgi?p=systembsd.git;a=summary) | partially | +| [localed](https://www.freedesktop.org/wiki/Software/systemd/localed) | D-Bus | yes | yes | GNOME | yes | [Ubuntu](https://launchpad.net/ubuntu/+source/ubuntu-system-service), [Gentoo](http://www.gentoo.org/proj/en/desktop/gnome/openrc-settingsd.xml), [BSD](http://uglyman.kremlin.cc/gitweb/gitweb.cgi?p=systembsd.git;a=summary) | partially | +| [timedated](https://www.freedesktop.org/wiki/Software/systemd/timedated) | D-Bus | yes | yes | GNOME | yes | [Gentoo](http://www.gentoo.org/proj/en/desktop/gnome/openrc-settingsd.xml), [BSD](http://uglyman.kremlin.cc/gitweb/gitweb.cgi?p=systembsd.git;a=summary) | partially | +| [initrd interface](https://www.freedesktop.org/wiki/Software/systemd/InitrdInterface) | Environment, flag files | yes | yes | dracut, ArchLinux | yes | ArchLinux | no | +| [Container interface](https://systemd.io/CONTAINER_INTERFACE) | Environment, Mounts | yes | yes | libvirt/LXC | yes | - | no | +| [Boot Loader interface](https://systemd.io/BOOT_LOADER_INTERFACE) | EFI variables | yes | yes | gummiboot | yes | - | no | +| [Service bus API](https://www.freedesktop.org/wiki/Software/systemd/dbus) | D-Bus | yes | yes | system-config-services | no | - | no | +| [logind](https://www.freedesktop.org/wiki/Software/systemd/logind) | D-Bus | yes | yes | GNOME | no | - | no | +| [sd-login.h API](https://www.freedesktop.org/software/systemd/man/sd-login.html) | C Library | yes | yes | GNOME, PolicyKit, ... | no | - | no | +| [sd-daemon.h API](https://www.freedesktop.org/software/systemd/man/sd-daemon.html) | C Library or Drop-in | yes | yes | numerous | yes | - | yes | +| [sd-id128.h API](https://www.freedesktop.org/software/systemd/man/sd-id128.html) | C Library | yes | yes | - | yes | - | no | +| [sd-journal.h API](https://www.freedesktop.org/software/systemd/man/sd-journal.html) | C Library | yes | yes | - | maybe | - | no | +| [$XDG_RUNTIME_DIR](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) | Environment | yes | yes | glib, GNOME | yes | - | no | +| [$LISTEN_FDS $LISTEN_PID FD Passing](https://www.freedesktop.org/software/systemd/man/sd_listen_fds.html) | Environment | yes | yes | numerous (via sd-daemon.h) | yes | - | no | +| [$NOTIFY_SOCKET Daemon Notifications](https://www.freedesktop.org/software/systemd/man/sd_notify.html) | Environment | yes | yes | a few, including udev | yes | - | no | +| [argv[0][0]='@' Logic](https://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons) | `/proc` marking | yes | yes | mdadm | yes | - | no | +| [Unit file format](https://www.freedesktop.org/software/systemd/man/systemd.unit.html) | File format | yes | yes | numerous | no | - | no | +| [Network](https://www.freedesktop.org/software/systemd/man/systemd.network.html) & [Netdev file format](https://www.freedesktop.org/software/systemd/man/systemd.netdev.html) | File format | yes | yes | no | no | - | no | +| [Link file format](https://www.freedesktop.org/software/systemd/man/systemd.link.html) | File format | yes | yes | no | no | - | no | +| [Journal File Format](https://www.freedesktop.org/wiki/Software/systemd/journal-files) | File format | yes | yes | - | maybe | - | no | +| [Journal Export Format](https://www.freedesktop.org/wiki/Software/systemd/export) | File format | yes | yes | - | yes | - | no | +| [Cooperation in cgroup tree](https://www.freedesktop.org/wiki/Software/systemd/PaxControlGroups) | Treaty | yes | yes | libvirt | yes | libvirt | no | +| [Password Agents](https://www.freedesktop.org/wiki/Software/systemd/PasswordAgents) | Socket+Files | yes | yes | - | yes | - | no | +| [udev multi-seat properties](https://www.freedesktop.org/wiki/Software/systemd/multiseat) | udev Property | yes | yes | X11, gdm | no | - | no | +| udev session switch ACL properties | udev Property | no | no | - | no | - | no | +| [CLI of systemctl,...](https://www.freedesktop.org/software/systemd/man/systemctl.html) | CLI | yes | yes | numerous | no | - | no | +| [tmpfiles.d](https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html) | File format | yes | yes | numerous | yes | ArchLinux | partially | +| [sysusers.d](https://www.freedesktop.org/software/systemd/man/sysusers.d.html) | File format | yes | yes | unknown | yes | | partially | +| [/etc/machine-id](https://www.freedesktop.org/software/systemd/man/machine-id.html) | File format | yes | yes | D-Bus | yes | - | no | +| [binfmt.d](https://www.freedesktop.org/software/systemd/man/binfmt.d.html) | File format | yes | yes | numerous | yes | - | partially | +| [/etc/hostname](https://www.freedesktop.org/software/systemd/man/hostname.html) | File format | yes | yes | numerous (it's a Debian thing) | yes | Debian, ArchLinux | no | +| [/etc/locale.conf](https://www.freedesktop.org/software/systemd/man/locale.conf.html) | File format | yes | yes | - | yes | ArchLinux | partially | +| [/etc/machine-info](https://www.freedesktop.org/software/systemd/man/machine-info.html) | File format | yes | yes | - | yes | - | partially | +| [modules-load.d](https://www.freedesktop.org/software/systemd/man/modules-load.d.html) | File format | yes | yes | numerous | yes | - | partially | +| [/usr/lib/os-release](https://www.freedesktop.org/software/systemd/man/os-release.html) | File format | yes | yes | some | yes | Fedora, OpenSUSE, ArchLinux, Angstrom, Frugalware, others... | no | +| [sysctl.d](https://www.freedesktop.org/software/systemd/man/sysctl.d.html) | File format | yes | yes | some (it's a Debian thing) | yes | procps/Debian, ArchLinux | partially | +| [/etc/timezone](https://www.freedesktop.org/software/systemd/man/timezone.html) | File format | yes | yes | numerous (it's a Debian thing) | yes | Debian | partially | +| [/etc/vconsole.conf](https://www.freedesktop.org/software/systemd/man/vconsole.conf.html) | File format | yes | yes | - | yes | ArchLinux | partially | +| `/run` | File hierarchy change | yes | yes | numerous | yes | OpenSUSE, Debian, ArchLinux | no | +| [Generators](https://www.freedesktop.org/software/systemd/man/systemd.generator.html) | Subprocess | yes | yes | - | no | - | no | +| [System Updates](https://www.freedesktop.org/software/systemd/man/systemd.offline-updates.html) | System Mode | yes | yes | - | no | - | no | +| [Presets](https://freedesktop.org/wiki/Software/systemd/Preset) | File format | yes | yes | - | no | - | no | +| Udev rules | File format | yes | yes | numerous | no | no | partially | + + +### Explanations + +Items for which "systemd implementation portable to other OSes" is "partially" means that it is possible to run the respective tools that are included in the systemd tarball outside of systemd. Note however that this is not officially supported, so you are more or less on your own if you do this. If you are opting for this solution simply build systemd as you normally would but drop all files except those which you are interested in. + +Of course, it is our intention to eventually document all interfaces we defined. If we haven't documented them for now, this is usually because we want the flexibility to still change things, or don't want 3rd party applications to make use of these interfaces already. That said, our sources are quite readable and open source, so feel free to spelunk around in the sources if you want to know more. + +If you decide to reimplement one of the APIs for which "Reimplementable independently" is "no", then we won't stop you, but you are on your own. + +This is not an attempt to comprehensively list all users of these APIs. We are just listing the most obvious/prominent ones which come to our mind. + +Of course, one last thing I can't make myself not ask you before we finish here, and before you start reimplementing these APIs in your distribution: are you sure it's time well spent if you work on reimplementing all this code instead of just spending it on adopting systemd on your distro as well? + +## Independent Operation of systemd Programs + +Some programs in the systemd suite are intended to operate independently of the +running init process (or even without an init process, for example when +creating system installation chroots). They can be safely called on systems with +a different init process or for example in package installation scriptlets. + +The following programs currently and in the future will support operation +without communicating with the `systemd` process: +`systemd-escape`, +`systemd-id128`, +`systemd-path`, +`systemd-tmpfiles`, +`systemd-sysctl`, +`systemd-sysusers`. + +Many other programs support operation without the system manager except when +the specific functionality requires such communication. For example +`journalctl` operates almost independently, but will query the boot id when +`--boot` option is used; it also requires `systemd-journald` (and thus +`systemd`) to be running for options like `--flush` and `--sync`. +`systemd-journal-remote`, `systemd-journal-upload`, `systemd-journal-gatewayd`, +`coredumpctl`, `busctl`, `systemctl --root` also fall into this category of +mostly-independent programs. diff --git a/docs/PORTABLE_SERVICES.md b/docs/PORTABLE_SERVICES.md index 194ef5bcd..8248275ce 100644 --- a/docs/PORTABLE_SERVICES.md +++ b/docs/PORTABLE_SERVICES.md @@ -1,5 +1,7 @@ --- title: Portable Services Introduction +category: Concepts +layout: default --- # Portable Services Introduction @@ -163,7 +165,7 @@ requirements are made for an image that can be attached/detached with an image with a partition table understood by the Linux kernel with only a single partition defined, or alternatively, a GPT partition table with a set of properly marked partitions following the [Discoverable Partitions - Specification](https://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/). + Specification](https://systemd.io/DISCOVERABLE_PARTITIONS). 3. The image must at least contain one matching unit file, with the right name prefix and suffix (see above). The unit file is searched in the usual paths, diff --git a/docs/PREDICTABLE_INTERFACE_NAMES.md b/docs/PREDICTABLE_INTERFACE_NAMES.md index b29016f93..07529e7a7 100644 --- a/docs/PREDICTABLE_INTERFACE_NAMES.md +++ b/docs/PREDICTABLE_INTERFACE_NAMES.md @@ -1,23 +1,24 @@ --- title: Predictable Network Interface Names +category: Concepts +layout: default --- # Predictable Network Interface Names -Starting with v197 systemd/udev will automatically assign predictable, stable network interface names for all local Ethernet, WLAN and WWAN interfaces. This is a departure from the traditional interface naming scheme ("eth0", "eth1", "wlan0", ...), but should fix real problems. - +Starting with v197 systemd/udev will automatically assign predictable, stable network interface names for all local Ethernet, WLAN and WWAN interfaces. This is a departure from the traditional interface naming scheme (`eth0`, `eth1`, `wlan0`, ...), but should fix real problems. ## Why? -The classic naming scheme for network interfaces applied by the kernel is to simply assign names beginning with "eth0", "eth1", ... to all interfaces as they are probed by the drivers. As the driver probing is generally not predictable for modern technology this means that as soon as multiple network interfaces are available the assignment of the names "eth0", "eth1" and so on is generally not fixed anymore and it might very well happen that "eth0" on one boot ends up being "eth1" on the next. This can have serious security implications, for example in firewall rules which are coded for certain naming schemes, and which are hence very sensitive to unpredictable changing names. +The classic naming scheme for network interfaces applied by the kernel is to simply assign names beginning with `eth0`, `eth1`, ... to all interfaces as they are probed by the drivers. As the driver probing is generally not predictable for modern technology this means that as soon as multiple network interfaces are available the assignment of the names `eth0`, `eth1` and so on is generally not fixed anymore and it might very well happen that `eth0` on one boot ends up being `eth1` on the next. This can have serious security implications, for example in firewall rules which are coded for certain naming schemes, and which are hence very sensitive to unpredictable changing names. -To fix this problem multiple solutions have been proposed and implemented. For a longer time udev shipped support for assigning permanent "ethX" names to certain interfaces based on their MAC addresses. This turned out to have a multitude of problems, among them: this required a writable root directory which is generally not available; the statelessness of the system is lost as booting an OS image on a system will result in changed configuration of the image; on many systems MAC addresses are not actually fixed, such as on a lot of embedded hardware and particularly on all kinds of virtualization solutions. The biggest of all however is that the userspace components trying to assign the interface name raced against the kernel assigning new names from the same "ethX" namespace, a race condition with all kinds of weird effects, among them that assignment of names sometimes failed. As a result support for this has been removed from systemd/udev a while back. +To fix this problem multiple solutions have been proposed and implemented. For a longer time udev shipped support for assigning permanent `ethX` names to certain interfaces based on their MAC addresses. This turned out to have a multitude of problems, among them: this required a writable root directory which is generally not available; the statelessness of the system is lost as booting an OS image on a system will result in changed configuration of the image; on many systems MAC addresses are not actually fixed, such as on a lot of embedded hardware and particularly on all kinds of virtualization solutions. The biggest of all however is that the userspace components trying to assign the interface name raced against the kernel assigning new names from the same `ethX` namespace, a race condition with all kinds of weird effects, among them that assignment of names sometimes failed. As a result support for this has been removed from systemd/udev a while back. -Another solution that has been implemented is "biosdevname" which tries to find fixed slot topology information in certain firmware interfaces and uses them to assign fixed names to interfaces which incorporate their physical location on the mainboard. In a way this naming scheme is similar to what is already done natively in udev for various device nodes via /dev/*/by-path/ symlinks. In many cases, biosdevname departs from the low-level kernel device identification schemes that udev generally uses for these symlinks, and instead invents its own enumeration schemes. +Another solution that has been implemented is `biosdevname` which tries to find fixed slot topology information in certain firmware interfaces and uses them to assign fixed names to interfaces which incorporate their physical location on the mainboard. In a way this naming scheme is similar to what is already done natively in udev for various device nodes via `/dev/*/by-path/` symlinks. In many cases, biosdevname departs from the low-level kernel device identification schemes that udev generally uses for these symlinks, and instead invents its own enumeration schemes. -Finally, many distributions support renaming interfaces to user-chosen names (think: "internet0", "dmz0", ...) keyed off their MAC addresses or physical locations as part of their networking scripts. This is a very good choice but does have the problem that it implies that the user is willing and capable of choosing and assigning these names. +Finally, many distributions support renaming interfaces to user-chosen names (think: `internet0`, `dmz0`, ...) keyed off their MAC addresses or physical locations as part of their networking scripts. This is a very good choice but does have the problem that it implies that the user is willing and capable of choosing and assigning these names. -We believe it is a good default choice to generalize the scheme pioneered by "biosdevname". Assigning fixed names based on firmware/topology/location information has the big advantage that the names are fully automatic, fully predictable, that they stay fixed even if hardware is added or removed (i.e. no reenumeration takes place) and that broken hardware can be replaced seamlessly. That said, they admittedly are sometimes harder to read than the "eth0" or "wlan0" everybody is used to. Example: "enp5s0" +We believe it is a good default choice to generalize the scheme pioneered by `biosdevname`. Assigning fixed names based on firmware/topology/location information has the big advantage that the names are fully automatic, fully predictable, that they stay fixed even if hardware is added or removed (i.e. no reenumeration takes place) and that broken hardware can be replaced seamlessly. That said, they admittedly are sometimes harder to read than the `eth0` or `wlan0` everybody is used to. Example: `enp5s0` ## What precisely has changed in v197? @@ -45,14 +46,14 @@ With this new scheme you now get: * Stable interface names even if you have to replace broken ethernet cards by new ones * The names are automatically determined without user configuration, they just work * The interface names are fully predictable, i.e. just by looking at lspci you can figure out what the interface is going to be called -* Fully stateless operation, changing the hardware configuration will not result in changes in /etc +* Fully stateless operation, changing the hardware configuration will not result in changes in `/etc` * Compatibility with read-only root -* The network interface naming now follows more closely the scheme used for aliasing block device nodes and other device nodes in /dev via symlinks +* The network interface naming now follows more closely the scheme used for aliasing block device nodes and other device nodes in `/dev` via symlinks * Applicability to both x86 and non-x86 machines * The same on all distributions that adopted systemd/udev * It's easy to opt out of the scheme (see below) -Does this have any drawbacks? Yes, it does. Previously it was practically guaranteed that hosts equipped with a single ethernet card only had a single "eth0" interface. With this new scheme in place, an administrator now has to check first what the local interface name is before he can invoke commands on it where previously he had a good chance that "eth0" was the right name. +Does this have any drawbacks? Yes, it does. Previously it was practically guaranteed that hosts equipped with a single ethernet card only had a single `eth0` interface. With this new scheme in place, an administrator now has to check first what the local interface name is before he can invoke commands on it where previously he had a good chance that `eth0` was the right name. ## I don't like this, how do I disable this? @@ -60,9 +61,9 @@ Does this have any drawbacks? Yes, it does. Previously it was practically guaran You basically have three options: 1. You disable the assignment of fixed names, so that the unpredictable kernel names are used again. For this, simply mask udev's .link file for the default policy: `ln -s /dev/null /etc/systemd/network/99-default.link` -1. You create your own manual naming scheme, for example by naming your interfaces "internet0", "dmz0" or "lan0". For that create your own .link files in /etc/systemd/network/, that choose an explicit name or a better naming scheme for one, some, or all of your interfaces. See [[systemd.link(5)|http://www.freedesktop.org/software/systemd/man/systemd.link.html]] for more information. -1. You pass the net.ifnames=0 on the kernel command line +1. You create your own manual naming scheme, for example by naming your interfaces `internet0`, `dmz0` or `lan0`. For that create your own `.link` files in `/etc/systemd/network/`, that choose an explicit name or a better naming scheme for one, some, or all of your interfaces. See [systemd.link(5)](http://www.freedesktop.org/software/systemd/man/systemd.link.html) for more information. +1. You pass the `net.ifnames=0` on the kernel command line ## How does the new naming scheme look like, precisely? -That's documented in detail in a comment block [[the sources of the net_id built-in|https://github.com/systemd/systemd/blob/master/src/udev/udev-builtin-net_id.c#L20]]. Please refer to this in case you are wondering how to decode the new interface names. +That's documented in detail the [systemd.net-naming-scheme(7)](https://www.freedesktop.org/software/systemd/man/systemd.net-naming-scheme.html) man page. Please refer to this in case you are wondering how to decode the new interface names. diff --git a/docs/RANDOM_SEEDS.md b/docs/RANDOM_SEEDS.md index 926238a3a..d3b68e967 100644 --- a/docs/RANDOM_SEEDS.md +++ b/docs/RANDOM_SEEDS.md @@ -1,5 +1,7 @@ --- title: Random Seeds +category: Concepts +layout: default --- # Random Seeds diff --git a/docs/RELEASE.md b/docs/RELEASE.md index 56debd68d..b56635a21 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -1,5 +1,7 @@ --- title: Steps to a Successful Release +category: Contributing +layout: default --- # Steps to a Successful Release diff --git a/docs/ROOT_STORAGE_DAEMONS.md b/docs/ROOT_STORAGE_DAEMONS.md new file mode 100644 index 000000000..779044b0d --- /dev/null +++ b/docs/ROOT_STORAGE_DAEMONS.md @@ -0,0 +1,193 @@ +--- +title: Storage Daemons for the Root File System +category: Interfaces +layout: default +--- + +# systemd and Storage Daemons for the Root File System + +a.k.a. _Pax Cellae pro Radix Arbor_ + +(or something like that, my Latin is a bit rusty) + +A number of complex storage technologies on Linux (e.g. RAID, volume +management, networked storage) require user space services to run while the +storage is active and mountable. This requirement becomes tricky as soon as the +root file system of the Linux operating system is stored on such storage +technology. Previously no clear path to make this work was available. This text +tries to clear up the resulting confusion, and what is now supported and what +is not. + +## A Bit of Background + +When complex storage technologies are used as backing for the root file system +this needs to be set up by the initial RAM file system (initrd), i.e. on Fedora +by Dracut. In newer systemd versions tear-down of the root file system backing +is also done by the initrd: after terminating all remaining running processes +and unmounting all file systems it can (which means excluding the root fs) +systemd will jump back into the initrd code allowing it to unmount the final +file systems (and its storage backing) that could not be unmounted as long as +the OS was still running from the main root file system. The initrd' job is to +detach/unmount the root fs, i.e. inverting the exact commands it used to set +them up in the first place. This is not only cleaner, but also allows for the +first time arbitrary complex stacks of storage technology. + +Previous attempts to handle root file system setups with complex storage as +backing usually tried to maintain the root storage with program code stored on +the root storage itself, thus creating a number of dependency loops. Safely +detaching such a root file system becomes messy, since the program code on the +storage needs to stay around longer than the storage, which is technically +contradicting. + + +## What's new? + +As a result, we hereby clarify that we do not support storage technology setups +where the storage daemons are being run from the storage it maintains +itself. In other words: a storage daemon backing the root file system cannot be +stored on the root file system itself. + +What we do support instead is that these storage daemons are started from the +initrd, stay running all the time during normal operation and are terminated +only after we returned control back to the initrd and by the initrd. As such, +storage daemons involved with maintaining the root file system storage +conceptually are more like kernel threads than like normal system services: +from the perspective of the init system (i.e. systemd) these services have been +started before systemd got initialized and stay around until after systemd is +already gone. These daemons can only be updated by updating the initrd and +rebooting, a takeover from initrd-supplied services to replacements from the +root file system is not supported. + + +## What does this mean? + +Near the end of system shutdown, systemd executes a small tool called +systemd-shutdown, replacing its own process. This tool (which runs as PID 1, as +it entirely replaces the systemd init process) then iterates through the +mounted file systems and running processes (as well as a couple of other +resources) and tries to unmount/read-only mount/detach/kill them. It continues +to do this in a tight loop as long as this results in any effect. From this +killing spree a couple of processes are automatically excluded: PID 1 itself of +course, as well as all kernel threads. After the killing/unmounting spree +control is passed back to the initrd, whose job is then to unmount/detach +whatever might be remaining. + +The same killing spree logic (but not the unmount/detach/read-only logic) is +applied during the transition from the initrd to the main system (i.e. the +"`switch_root`" operation), so that no processes from the initrd survive to the +main system. + +To implement the supported logic proposed above (i.e. where storage daemons +needed for the root fs which are started by the initrd stay around during +normal operation and are only killed after control is passed back to the +initrd) we need to exclude these daemons from the shutdown/switch_root killing +spree. To accomplish this the following logic is available starting with +systemd 38: + +Processes (run by the root user) whose first character of the zeroth command +line argument is `@` are excluded from the killing spree, much the same way as +kernel threads are excluded too. Thus, a daemon which wants to take advantage +of this logic needs to place the following at the top of its `main()` function: + +```c +... +argv[0][0] = '@'; +... +``` + +And that's already it. Note that this functionality is only to be used by +programs running from the initrd, and **not** for programs running from the +root file system itself. Programs which use this functionality and are running +from the root file system are considered buggy since they effectively prohibit +clean unmounting/detaching of the root file system and its backing storage. + +_Again: if your code is being run from the root file system, then this logic +suggested above is **NOT** for you. Sorry. Talk to us, we can probably help you +to find a different solution to your problem._ + +The recommended way to distinguish between run-from-initrd and run-from-rootfs +for a daemon is to check for `/etc/initrd-release` (which exists on all modern +initrd implementations, see the [initrd +Interface](http://www.freedesktop.org/wiki/Software/systemd/InitrdInterface) +for details) which when exists results in `argv[0][0]` being set to `@`, and +otherwise doesn't. Something like this: + +```c +#include + +int main(int argc, char *argv[]) { + ... + if (access("/etc/initrd-release", F_OK) >= 0) + argv[0][0] = '@'; + ... + } +``` + +Why `@`? Why `argv[0][0]`? First of all, a technique like this is not without +precedent: traditionally Unix login shells set `argv[0][0]` to `-` to clarify +they are login shells. This logic is also very easy to implement. We have been +looking for other ways to mark processes for exclusion from the killing spree, +but could not find any that was equally simple to implement and quick to read +when traversing through `/proc/`. Also, as a side effect replacing the first +character of `argv[0]` with `@` also visually invalidates the path normally +stored in `argv[0]` (which usually starts with `/`) thus helping the +administrator to understand that your daemon is actually not originating from +the actual root file system, but from a path in a completely different +namespace (i.e. the initrd namespace). Other than that we just think that `@` +is a cool character which looks pretty in the ps output... 😎 + +Note that your code should only modify `argv[0][0]` and leave the comm name +(i.e. `/proc/self/comm`) of your process untouched. + +## To which technologies does this apply? + +These recommendations apply to those storage daemons which need to stay around +until after the storage they maintain is unmounted. If your storage daemon is +fine with being shut down before its storage device is unmounted you may ignore +the recommendations above. + +This all applies to storage technology only, not to daemons with any other +(non-storage related) purposes. + +## What else to keep in mind? + +If your daemon implements the logic pointed out above it should work nicely +from initrd environments. In many cases it might be necessary to additionally +support storage daemons to be started from within the actual OS, for example +when complex storage setups are used for auxiliary file systems, i.e. not the +root file system, or created by the administrator during runtime. Here are a +few additional notes for supporting these setups: + +* If your storage daemon is run from the main OS (i.e. not the initrd) it will + also be terminated when the OS shuts down (i.e. before we pass control back + to the initrd). Your daemon needs to handle this properly. + +* It is not acceptable to spawn off background processes transparently from + user commands or udev rules. Whenever a process is forked off on Unix it + inherits a multitude of process attributes (ranging from the obvious to the + not-so-obvious such as security contexts or audit trails) from its parent + process. It is practically impossible to fully detach a service from the + process context of the spawning process. In particular, systemd tracks which + processes belong to a service or login sessions very closely, and by spawning + off your storage daemon from udev or an administrator command you thus make + it part of its service/login. Effectively this means that whenever udev is + shut down, your storage daemon is killed too, resp. whenever the login + session goes away your storage might be terminated as well. (Also note that + recent udev versions will automatically kill all long running background + processes forked off udev rules now.) So, in summary: double-forking off + processes from user commands or udev rules is **NOT** OK! + +* To automatically spawn storage daemons from udev rules or administrator + commands, the recommended technology is socket-based activation as + implemented by systemd. Transparently for your client code connecting to the + socket of your storage daemon will result in the storage to be started. For + that it is simply necessary to inform systemd about the socket you'd like it + to listen on on behalf of your daemon and minimally modify the daemon to + receive the listening socket for its services from systemd instead of + creating it on its own. Such modifications can be minimal, and are easily + written in a way that does not negatively impact usability on non-systemd + systems. For more information on making use of socket activation in your + program consult this blog story: [Socket + Activation](http://0pointer.de/blog/projects/socket-activation.html) + +* Consider having a look at the [initrd Interface of systemd](https://systemd.io/INITRD_INTERFACE/). diff --git a/docs/SECURITY.md b/docs/SECURITY.md index 93847dcd8..0b34e5325 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -1,7 +1,9 @@ --- -title: Reporting of security vulnerabilities +title: Reporting of Security Vulnerabilities +category: Contributing +layout: default --- -# Reporting of security vulnerabilities +# Reporting of Security Vulnerabilities If you discover a security vulnerability, we'd appreciate a non-public disclosure. The [issue tracker](https://github.com/systemd/systemd/issues) and [systemd-devel mailing list](https://lists.freedesktop.org/mailman/listinfo/systemd-devel) are fully public. If you need to reach systemd developers in a non-public way, report the issue to the [systemd-security@redhat.com](mailto:systemd-security@redhat.com) mailing list. The disclosure will be coordinated with distributions. diff --git a/docs/TEMPORARY_DIRECTORIES.md b/docs/TEMPORARY_DIRECTORIES.md index 9271e0e47..5bb24fa3e 100644 --- a/docs/TEMPORARY_DIRECTORIES.md +++ b/docs/TEMPORARY_DIRECTORIES.md @@ -1,5 +1,7 @@ --- title: Using /tmp/ And /var/tmp/ Safely +category: Interfaces +layout: default --- # Using `/tmp/` And `/var/tmp/` Safely diff --git a/docs/TESTING_WITH_SANITIZERS.md b/docs/TESTING_WITH_SANITIZERS.md index 7cb879aaf..2622682bd 100644 --- a/docs/TESTING_WITH_SANITIZERS.md +++ b/docs/TESTING_WITH_SANITIZERS.md @@ -1,8 +1,10 @@ --- -title: Testing systemd using sanitizers +title: Testing systemd Using Sanitizers +category: Contributing +layout: default --- -# Testing systemd using sanitizers +# Testing systemd Using Sanitizers To catch the *nastier* kind of bugs, you can run your code with [Address Sanitizer](https://clang.llvm.org/docs/AddressSanitizer.html) and [Undefined Behavior Sanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html). diff --git a/docs/TRANSIENT-SETTINGS.md b/docs/TRANSIENT-SETTINGS.md index 6cbd03e1a..271d8ab1e 100644 --- a/docs/TRANSIENT-SETTINGS.md +++ b/docs/TRANSIENT-SETTINGS.md @@ -1,8 +1,10 @@ --- -title: What settings are currently available for transient units? +title: What Settings Are Currently Available For Transient Units? +category: Interfaces +layout: default --- -# What settings are currently available for transient units? +# What Settings Are Currently Available For Transient Units? Our intention is to make all settings that are available as unit file settings also available for transient units, through the D-Bus API. At the moment, @@ -190,6 +192,7 @@ All execution-related settings are available for transient units. ✓ PrivateUsers= ✓ ProtectSystem= ✓ ProtectHome= +✓ ProtectClock= ✓ MountFlags= ✓ MountAPIVFS= ✓ Personality= diff --git a/docs/TRANSLATORS.md b/docs/TRANSLATORS.md index d155c1c87..a120bcafb 100644 --- a/docs/TRANSLATORS.md +++ b/docs/TRANSLATORS.md @@ -1,5 +1,7 @@ --- title: Notes for Translators +category: Contributing +layout: default --- # Notes for Translators @@ -67,7 +69,7 @@ Once you're done, create a git commit for the update of the `po/*.po` file you touched. Remember to undo the changes to the other `*.po` files (for instance, using `git checkout -- po/` after you commit the changes you do want to keep.) -# Recompiling Translations +## Recompiling Translations You can recompile the `*.po` files using the following command: diff --git a/docs/UIDS-GIDS.md b/docs/UIDS-GIDS.md index 1f3966f4c..255cc7132 100644 --- a/docs/UIDS-GIDS.md +++ b/docs/UIDS-GIDS.md @@ -1,8 +1,10 @@ --- -title: Users, Groups, UIDs and GIDs on `systemd` Systems +title: Users, Groups, UIDs and GIDs on systemd Systems +category: Concepts +layout: default --- -# Users, Groups, UIDs and GIDs on `systemd` Systems +# Users, Groups, UIDs and GIDs on systemd Systems Here's a summary of the requirements `systemd` (and Linux) make on UID/GID assignments and their ranges. @@ -94,7 +96,15 @@ but downstreams are strongly advised against doing that.) `systemd` defines a number of special UID ranges: -1. 61184…65519 → UIDs for dynamic users are allocated from this range (see the +1. 60001…60513 → UIDs for home directories managed by + [`systemd-homed.service(8)`](https://www.freedesktop.org/software/systemd/man/systemd-homed.service.html). UIDs + from this range are automatically assigned to any home directory discovered, + and persisted locally on first login. On different systems the same user + might get different UIDs assigned in case of conflict, though it is + attempted to make UID assignments stable, by deriving them from a hash of + the user name. + +2. 61184…65519 → UIDs for dynamic users are allocated from this range (see the `DynamicUser=` documentation in [`systemd.exec(5)`](https://www.freedesktop.org/software/systemd/man/systemd.exec.html)). This range has been chosen so that it is below the 16bit boundary (i.e. below @@ -109,7 +119,7 @@ but downstreams are strongly advised against doing that.) user record resolving works correctly without those users being in `/etc/passwd`. -2. 524288…1879048191 → UID range for `systemd-nspawn`'s automatic allocation of +3. 524288…1879048191 → UID range for `systemd-nspawn`'s automatic allocation of per-container UID ranges. When the `--private-users=pick` switch is used (or `-U`) then it will automatically find a so far unused 16bit subrange of this range and assign it to the container. The range is picked so that the upper @@ -230,7 +240,8 @@ the artifacts the container manager persistently leaves in the system. | 5 | `tty` group | `systemd` | `/etc/passwd` | | 6…999 | System users | Distributions | `/etc/passwd` | | 1000…60000 | Regular users | Distributions | `/etc/passwd` + LDAP/NIS/… | -| 60001…61183 | Unused | | | +| 60001…60513 | Human Users (homed) | `systemd` | `nss-systemd` +| 60514…61183 | Unused | | | | 61184…65519 | Dynamic service users | `systemd` | `nss-systemd` | | 65520…65533 | Unused | | | | 65534 | `nobody` user | Linux | `/etc/passwd` + `nss-systemd` | diff --git a/docs/USER_GROUP_API.md b/docs/USER_GROUP_API.md new file mode 100644 index 000000000..21d498f5f --- /dev/null +++ b/docs/USER_GROUP_API.md @@ -0,0 +1,267 @@ +--- +title: User/Group Record Lookup API via Varlink +category: Interfaces +layout: default +--- + +# User/Group Record Lookup API via Varlink + +JSON User/Group Records (as described in the [JSON User +Records](https://systemd.io/USER_RECORD) and [JSON Group +Records](https://systemd.io/GROUP_RECORD) documents) that are defined on the +local system may be queried with a [Varlink](https://varlink.org/) API. This +API takes both the role of what +[`getpwnam(3)`](http://man7.org/linux/man-pages/man3/getpwnam.3.html) and +related calls are for `struct passwd`, as well as the interfaces modules +implementing the [glibc Name Service Switch +(NSS)](https://www.gnu.org/software/libc/manual/html_node/Name-Service-Switch.html) +expose. Or in other words, it both allows applications to efficiently query +user/group records from local services, and allows local subsystems to provide +user/group records efficiently to local applications. + +This simple API only exposes only three method calls, and requires only a small +subset of the Varlink functionality. + +## Why Varlink? + +The API described in this document is based on a simple subset of the +mechanisms described by [Varlink](https://varlink.org/). The choice of +preferring Varlink over D-Bus and other IPCs in this context was made for three +reasons: + +1. User/Group record resolution should work during early boot and late shutdown + without special handling. This is very hard to do with D-Bus, as the broker + service for D-Bus generally runs as regular system daemon and is hence only + available at the latest boot stage. + +2. The JSON user/group records are native JSON data, hence picking an IPC + system that natively operates with JSON data is natural and clean. + +3. IPC systems such as D-Bus do not provide flow control and are thus unusable + for streaming data. They are useful to pass around short control messages, + but as soon as potentially many and large objects shall be transferred, + D-Bus is not suitable, as any such streaming of messages would be considered + flooding in D-Bus' logic, and thus possibly result in termination of + communication. Since the APIs defined in this document need to support + enumerating potentially large numbers of users and groups, D-Bus is simply + not an appropriate option. + +## Concepts + +Each subsystem that needs to define users and groups on the local system is +supposed to implement this API, and offer its interfaces on a Varlink +`AF_UNIX`/`SOCK_STREAM` file system socket bound into the +`/run/systemd/userdb/` directory. When a client wants to look up a user or +group record, it contacts all sockets bound in this directory in parallel, and +enqueues the same query to each. The first positive reply is then returned to +the application, or if all fail the last seen error is returned +instead. (Alternatively a special Varlink service is available, +`io.systemd.Multiplexer` which acts as frontend and will do the parallel +queries on behalf of the client, drastically simplifying client +development. This service is not available during earliest boot and final +shutdown phases.) + +Unlike with glibc NSS there's no order or programmatic expression language +defined in which queries are issued to the various services. Instead, all +queries are always enqueued in parallel to all defined services, in order to +make look-ups efficient, and the simple rule of "first successful lookup wins" +is unconditionally followed for user and group look-ups (though not for +membership lookups, see below). + +This simple scheme only works safely as long as every service providing +user/group records carefully makes sure not to answer with conflicting +records. This API does not define any mechanisms for dealing with user/group +name/ID collisions during look-up nor during record registration. It assumes +the various subsystems that want to offer user and group records to the rest of +the system have made sufficiently sure in advance that their definitions do not +collide with those of other services. Clients are not expected to merge +multiple definitions for the same user or group, and will also not be able to +detect conflicts and suppress such conflicting records. + +It is recommended to name the sockets in the directory in reverse domain name +notation, but this is neither required nor enforced. + +## Well-Known Services + +Any subsystem that wants to provide user/group records can do so, simply by +binding a socket in the aforementioned directory. By default two +services are listening there, that have special relevance: + +1. `io.systemd.NameServiceSwitch` → This service makes the classic UNIX/glibc + NSS user/group records available as JSON User/Group records. Any such + records are automatically converted as needed, and possibly augmented with + information from the shadow databases. + +2. `io.systemd.Multiplexer` → This service multiplexes client queries to all + other running services. It's supposed to simplify client development: in + order to look up or enumerate user/group records it's sufficient to talk to + one service instead of all of them in parallel. Note that it is not availabe + during earliest boot and final shutdown phases, hence for programs running + in that context it is preferable to implement the parallel lookup + themselves. + +Both these services are implemented by the same daemon +`systemd-userdbd.service`. + +Note that these services currently implement a subset of Varlink only. For +example, introspection is not available, and the resolver logic is not used. + +## Other Services + +The `systemd` project provides two other services implementing this +interface. Specifically: + +1. `io.systemd.DynamicUser` → This service is implemented by the service + manager itself, and provides records for the users and groups synthesized + via `DynamicUser=` in unit files. + +2. `io.systemd.Home` → This service is implemented by `systemd-homed.service` + and provides records for the users and groups defined by the home + directories it manages. + +Other projects are invited to implement these services too. For example it +would make sense for LDAP/ActiveDirectory projects to implement these +interfaces, which would provide them a way to do per-user resource management +enforced by systemd and defined directly in LDAP directories. + +## Compatibility with NSS + +Two-way compatibility with classic UNIX/glibc NSS user/group records is +provided. When using the Varlink API, lookups into databases provided only via +NSS (and not natively via Varlink) are handled by the +`io.systemd.NameServiceSwitch` service (see above). When using the NSS API +(i.e. `getpwnam()` and friends) the `nss-systemd` module will automatically +synthesize NSS records for users/groups natively defined via a Varlink +API. Special care is taken to avoid recursion between these two compatibility +mechanisms. + +Subsystems that shall provide user/group records to the system may choose +between offering them via an NSS module or via a this Varlink API, either way +all records are accessible via both APIs, due to the bidirectional +forwarding. It is also possible to provide the same records via both APIs +directly, but in that case the compatibility logic must be turned off. There +are mechanisms in place for this, please contact the systemd project for +details, as these are currently not documented. + +## Caching of User Records + +This API defines no concepts for caching records. If caching is desired it +should be implemented in the subsystems that provide the user records, not in +the clients consuming them. + +## Method Calls + +``` +interface io.systemd.UserDatabase + +method GetUserRecord( + uid : ?int, + userName : ?string, + service : string +) -> ( + record : object, + incomplete : boolean +) + +method GetGroupRecord( + gid : ?int, + groupName : ?string, + service : string +) -> ( + record : object, + incomplete : boolean +) + +method GetMemberships( + userName : ?string, + groupName : ?string, + service : string +) -> ( + userName : string, + groupName : string +) + +error NoRecordFound() +error BadService() +error ServiceNotAvailable() +error ConflictingRecordFound() +``` + +The `GetUserRecord` method looks up or enumerates a user record. If the `uid` +parameter is set it specifies the numeric UNIX UID to search for. If the +`userName` parameter is set it specifies the name of the user to search +for. Typically, only one of the two parameters are set, depending whether a +look-up by UID or by name is desired. However, clients may also specify both +parameters, in which case a record matching both will be returned, and if only +one exists that matches one of the two parameters but not the other an error of +`ConflictingRecordFound` is returned. If neither of the two parameters are set +the whole user database is enumerated. In this case the method call needs to be +made with `more` set, so that multiple method call replies may be generated as +effect, each carrying one user record. + +The `service` parameter is mandatory and should be set to the service name +being talked to (i.e. to the same name as the `AF_UNIX` socket path, with the +`/run/systemd/userdb/` prefix removed). This is useful to allow implementation +of multiple services on the same socket (which is used by +`systemd-userdbd.service`). + +The method call returns one or more user records, depending which type of query is +used (see above). The record is returned in the `record` field. The +`incomplete` field indicates whether the record is complete. Services providing +user record lookup should only pass the `privileged` section of user records to +clients that either match the user the record is about or to sufficiently +privileged clients, for all others the section must be removed so that no +sensitive data is leaked this way. The `incomplete` parameter should indicate +whether the record has been modified like this or not (i.e. it is `true` if a +`privileged` section existed in the user record and was removed, and `false` if +no `privileged` section existed or one existed but hasn't been removed). + +If no user record matching the specified UID or name is known the error +`NoRecordFound` is returned (this is also returned if neither UID nor name are +specified, and hence enumeration requested but the subsystem currently has no +users defined). + +If a method call with an incorrectly set `service` field is received +(i.e. either not set at all, or not to the service's own name) a `BadService` +error is generated. Finally, `ServiceNotAvailable` should be returned when the +backing subsystem is not operational for some reason and hence no information +about existence or non-existence of a record can be returned nor any user +record at all. (The `service` field is defined in order to allow implementation +of daemons that provide multiple distinct user/group services over the same +`AF_UNIX` socket: in order to correctly determine which service a client wants +to talk to the client needs to provide the name in each request.) + +The `GetGroupRecord` method call works analogously but for groups. + +The `GetMemberships` method call may be used to inquire about group +memberships. The `userName` and `groupName` arguments take what the name +suggests. If one of the two is specified all matching memberships are returned, +if neither is specified all known memberships of any user and any group are +returned. The return value is a pair of user name and group name, where the +user is a member of the group. If both arguments are specified the specified +membership will be tested for, but no others, and the pair is returned if it is +defined. Unless both arguments are specified the method call needs to be made +with `more` set, so that multiple replies can be returned (since typically +there are are multiple members per group and also multiple groups a user is +member of). As with `GetUserRecord` and `GetGroupRecord` the `service` +parameter needs to contain the name of the service being talked to, in order to +allow implementation of multiple service within the same IPC socket. In case no +matching membership is known `NoRecordFound` is returned. The other two errors +are also generated in the same cases as for `GetUserRecord` and +`GetGroupRecord`. + +Unlike with `GetUserRecord` and `GetGroupRecord` the lists of memberships +returned by services are always combined. Thus unlike the other two calls a +membership lookup query has to wait for the last simultaneous query to complete +before the complete list is acquired. + +Note that only the `GetMemberships` call is authoritative about memberships of +users in groups. i.e. it should not be considered sufficient to check the +`memberOf` field of user records and the `members` field of group records to +acquire the full list of memberships. The full list can only bet determined by +`GetMemberships`, and as mentioned requires merging of these lists of all local +services. Result of this is that it can be one service that defines a user A, +and another service that defines a group B, and a third service that declares +that A is a member of B. + +And that's really all there is to it. diff --git a/docs/USER_RECORD.md b/docs/USER_RECORD.md new file mode 100644 index 000000000..299aaade4 --- /dev/null +++ b/docs/USER_RECORD.md @@ -0,0 +1,1023 @@ +--- +title: JSON User Records +category: Interfaces +layout: default +--- + +# JSON User Records + +systemd optionally processes user records that go beyond the classic UNIX (or +glibc NSS) `struct passwd`. Various components of systemd are able to provide +and consume records in a more extensible format of a dictionary of key/value +pairs, encoded as JSON. Specifically: + +1. [`systemd-homed.service`](https://www.freedesktop.org/software/systemd/man/systemd-homed.service.html) + manages `human` user home directories and embeds these JSON records + directly in the home directory images (see [Home + Directories](https://systemd.io/HOME_DIRECTORY)) for details. + +2. [`pam_systemd`](https://www.freedesktop.org/software/systemd/man/pam_systemd.html) + processes these JSON records for users that log in, and applies various + settings to the activated session, including environment variables, nice + levels and more. + +3. [`systemd-logind.service`](https://www.freedesktop.org/software/systemd/man/systemd-logind.service.html) + processes these JSON records of users that log in, and applies various + resource management settings to the per-user slice units it manages. This + allows setting global limits on resource consumption by a specific user. + +4. [`nss-systemd`](https://www.freedesktop.org/software/systemd/man/nss-systemd.html) + is a glibc NSS module that synthesizes classic NSS records from these JSON + records, providing full backwards compatibility with the classic UNIX APIs + both for look-up and enumeration. + +5. The service manager (PID 1) exposes dynamic users (i.e. users synthesized as + effect of `DynamicUser=` in service unit files) as these advanced JSON + records, making them discoverable to the rest of the system. + +6. [`systemd-userdbd.service`](https://www.freedesktop.org/software/systemd/man/systemd-userdbd.service.html) + is a small service that can translate UNIX/glibc NSS records to these JSON + user records. It also provides a unified [Varlink](https://varlink.org/) API + for querying and enumerating records of this type, optionally acquiring them + from various other services. + +JSON user records may contain various fields that are not available in `struct +passwd`, and are extensible for other applications. For example, the record may +contain information about: + +1. Additional security credentials (PKCS#11 security token information, + biometrical authentication information, SSH public key information) + +2. Additional user metadata, such as a picture, email address, location string, + preferred language or timezone + +3. Resource Management settings (such as CPU/IO weights, memory and tasks + limits, classic UNIX resource limits or nice levels) + +4. Runtime parameters such as environment variables or the `nodev`, `noexec`, + `nosuid` flags to use for the home directory + +5. Information about where to mount the home directory from + +And various other things. The record is intended to be extensible, for example +the following extensions are envisioned: + +1. Windows network credential information + +2. Information about default IMAP, SMTP servers to use for this user + +3. Parental control information to enforce on this user + +4. Default parameters for backup applications and similar + +Similar to JSON User Records there are also [JSON Group +Records](https://systemd.io/GROUP_RECORD) that encapsulate UNIX groups. + +JSON User Records may be transferred or written to disk in various protocols +and formats. To inquire about such records defined on the local system use the +[User/Group Lookup API via Varlink](https://systemd.io/USER_GROUP_API). + +## Why JSON? + +JSON is nicely extensible and widely used. In particular it's easy to +synthesize and process with numerous programming languages. It's particularly +popular in the web communities, which hopefully should make it easy to link +user credential data from the web and from local systems more closely together. + +## General Structure + +The JSON user records generated and processed by systemd follow a general +structure, consisting of seven distinct "sections". Specifically: + +1. Various fields are placed at the top-level of user record (the `regular` + section). These are generally fields that shall apply unconditionally to the + user in all contexts, are portable and not security sensitive. + +2. A number of fields are located in the `privileged` section (a sub-object of + the user record). Fields contained in this object are security sensitive, + i.e. contain information that the user and the administrator should be able + to see, but other users should not. In many ways this matches the data + stored in `/etc/shadow` in classic Linux user accounts, i.e. includes + password hashes and more. Algorithmically, when a user record is passed to + an untrusted client, by monopolizing such sensitive records in a single + object field we can easily remove it from view. + +3. A number of fields are located in objects inside the `perMachine` section + (an array field of the user record). Primarily these are resource + management-related fields, as those tend to make sense on a specific system + only, e.g. limiting a user's memory use to 1G only makes sense on a specific + system that has more than 1G of memory. Each object inside the `perMachine` + array comes with a `matchMachineId` or `matchHostname` field which indicate + which systems to apply the listed settings to. Note that many fields + accepted in the `perMachine` section can also be set at the top level (the + `regular` section), where they define the fallback if no matching object in + `perMachine` is found. + +4. Various fields are located in the `binding` section (a sub-sub-object of the + user record; an intermediary object is inserted which is keyed by the + machine ID of the host). Fields included in this section "bind" the object + to a specific system. They generally include non-portable information about + paths or UID assignments, that are true on a specific system, but not + necessarily on others, and which are managed automatically by some user + record manager (such as `systemd-homed`). Data in this section is considered + part of the user record only in the local context, and is generally not + ported to other systems. Due to that it is not included in the reduced user + record the cryptographic signature defined in the `signature` section is + calculated on. In `systemd-homed` this section is also removed when the + user's record is stored in the `~/.identity` file in the home directory, so + that every system with access to the home directory can manage these + `binding` fields individually. Typically, the binding section is persisted + to the local disk. + +5. Various fields are located in the `status` section (a sub-sub-object of the + user record, also with an intermediary object between that is keyed by the + machine ID, similar to the way the `binding` section is organized). This + section is augmented during runtime only, and never persisted to disk. The + idea is that this section contains information about current runtime + resource usage (for example: currently used disk space of the user), that + changes dynamically but is otherwise immediately associated with the user + record and for many purposes should be considered to be part of the user + record. + +6. The `signature` section contains one or more cryptographic signatures of a + reduced version of the user record. This is used to ensure that only user + records defined by a specific source are accepted on a system, by validating + the signature against the set of locally accepted signature public keys. The + signature is calculated from the JSON user record with all sections removed, + except for `regular`, `privileged`, `perMachine`. Specifically, `binding`, + `status`, `signature` itself and `secret` are removed first and thus not + covered by the signature. This section is optional, and is only used when + cryptographic validation of user records is required (as it is by + `systemd-homed.service` for example). + +7. The `secret` section contains secret user credentials, such as password or + PIN information. This data is never persisted, and never returned when user + records are inquired by a client, privileged or not. This data should only + be included in a user record very briefly, for example when certain very + specific operations are executed. For example, in tools such as + `systemd-homed` this section may be included in user records, when creating + a new home directory, as passwords and similar credentials need to be + provided to encrypt the home directory with. + +Here's a tabular overview of the sections and their properties: + +| Section | Included in Signature | Persistent | Security Sensitive | Contains Host-Specific Data | +|------------|-----------------------|------------|--------------------|-----------------------------| +| regular | yes | yes | no | no | +| privileged | yes | yes | yes | no | +| perMachine | yes | yes | no | yes | +| binding | no | yes | no | yes | +| status | no | no | no | yes | +| signature | no | yes | no | no | +| secret | no | no | yes | no | + +Note that services providing user records to the local system are free to +manage only a subset of these sections and never include the others in +them. For example, a service that has no concept of signed records (for example +because the records it manages are inherently trusted anyway) does not have to +bother with the `signature` section. A service that only defines records in a +strictly local context and without signatures doesn't have to deal with the +`perMachine` or `binding` sections and can include its data exclusively in the +regular section. A service that uses a separate, private channel for +authenticating users (or that doesn't have a concept of authentication at all) +does not need to to be concerned with the `secret` section of user records, as +the fields included therein are only useful when executing authentication +operations natively against JSON user records. + +The `systemd-homed` manager uses all seven sections for various +purposes. Inside the home directories (and if the LUKS2 backend is used, also +in the LUKS2 header) a user record containing the `regular`, `privileged`, +`perMachine` and `signature` sections is stored. `systemd-homed` also stores a +version of the record on the host, with the same four sections and augmented +with an additional, fifth `binding` section. When a local client enquires about +a user record managed by `systemd-homed` the service will add in some +additional information about the user and home directory in the `status` +section — this version is only transferred via IPC and never written to +disk. Finally the `secret` section is used during authentication operations via +IPC to transfer the user record along with its authentication tokens in one go. + +## Fields in the `regular` section + +As mentioned, the `regular` section's fields are placed at the top level +object. The following fields are currently defined: + +`userName` → The UNIX user name for this record. Takes a string with a valid +UNIX user name. This field is the only mandatory field, all others are +optional. Corresponds with the `pw_name` field of of `struct passwd` and the +`sp_namp` field of `struct spwd` (i.e. the shadow user record stored in +`/etc/shadow`). + +`realm` → The "realm" a user is defined in. This concept allows distinguishing +users with the same name that originate in different organizations or +installations. This should take a string in DNS domain syntax, but doesn't have +to refer to an actual DNS domain (though it is recommended to use one for +this). The idea is that the user `lpoetter` in the `redhat.com` realm might be +distinct from the same user in the `poettering.hq` realm. User records for the +same user name that have different realm fields are considered referring to +different users. When updating a user record it is required that any new +version has to match in both `userName` and `realm` field. This field is +optional, when unset the user should not be considered part of any realm. A +user record with a realm set is never compatible (for the purpose of updates, +see above) with a user record without one set, even if the `userName` field matches. + +`realName` → The real name of the user, a string. This should contain the user's +real ("human") name, and corresponds loosely to the GECOS field of classic UNIX +user records. When converting a `struct passwd` to a JSON user record this +field is initialized from GECOS (i.e. the `pw_gecos` field), and vice versa +when converting back. That said, unlike GECOS this field is supposed to contain +only the real name and no other information. + +`emailAddress` → The email address of the user, formatted as +string. [`pam_systemd`](https://www.freedesktop.org/software/systemd/man/pam_systemd.html) +initializes the `$EMAIL` environment variable from this value for all login +sessions. + +`iconName` → The name of an icon picked by the user, for example for the +purpose of an avatar. This must be a string, and should follow the semantics +defined in the [Icon Naming +Specification](https://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html). + +`location` → A free-form location string describing the location of the user, +if that is applicable. It's probably wise to use a location string processable +by geo-location subsystems, but this is not enforced nor required. Example: +`Berlin, Germany` or `Basement, Room 3a`. + +`disposition` → A string, one of `intrinsic`, `system`, `dynamic`, `regular`, +`container`, `reserved`. If specified clarifies the disposition of the user, +i.e. the context it is defined in. For regular, "human" users this should be +`regular`, for system users (i.e. users that system services run under, and +similar) this should be `system`. The `intrinsic` disposition should be used +only for the two users that have special meaning to the OS kernel itself, +i.e. the `root` and `nobody` users. The `container` string should be used for +users that are used by an OS container, and hence will show up in `ps` listings +and such, but are only defined in container context. Finally `reserved` should +be used for any users outside of these use-cases. Note that this property is +entirely optional and applications are assumed to be able to derive the +disposition of a user automatically from a record even in absence of this +field, based on other fields, for example the numeric UID. By setting this +field explicitly applications can override this default determination. + +`lastChangeUSec` → An unsigned 64bit integer value, referring to a timestamp in µs +since the epoch 1970, indicating when the user record (specifically, any of the +`regular`, `privileged`, `perMachine` sections) was last changed. This field is +used when comparing two records of the same user to identify the newer one, and +is used for example for automatic updating of user records, where appropriate. + +`lastPasswordChangeUSec` → Similar, also an unsigned 64bit integer value, +indicating the point in time the password (or any authentication token) of the +user was last changed. This corresponds to the `sp_lstchg` field of `struct +spwd`, i.e. the matching field in the user shadow database `/etc/shadow`, +though provides finer resolution. + +`shell` → A string, referring to the shell binary to use for terminal logins of +this user. This corresponds with the `pw_shell` field of `struct passwd`, and +should contain an absolute file system path. For system users not suitable for +terminal log-in this field should not be set. + +`umask` → The `umask` to set for the user's login sessions. Takes an +integer. Note that usually on UNIX the umask is noted in octal, but JSON's +integers are generally written in decimal, hence in this context we denote it +umask in decimal too. The specified value should be in the valid range for +umasks, i.e. 0000…0777 (in octal as typical in UNIX), or 0…511 (in decimal, how +it actually appears in the JSON record). This `umask` is automatically set by +[`pam_systemd`](https://www.freedesktop.org/software/systemd/man/pam_systemd.html) +for all login sessions of the user. + +`environment` → An array of strings, each containing an environment variable +and its value to set for the user's login session, in a format compatible with +[`putenv()`](http://man7.org/linux/man-pages/man3/putenv.3.html). Any +environment variable listed here is automatically set by +[`pam_systemd`](https://www.freedesktop.org/software/systemd/man/pam_systemd.html) +for all login sessions of the user. + +`timeZone` → A string indicating a preferred timezone to use for the user. When +logging in +[`pam_systemd`](https://www.freedesktop.org/software/systemd/man/pam_systemd.html) +will automatically initialize the `$TZ` environment variable from this +string. The string should be a `tzdata` compatible location string, for +example: `Europe/Berlin`. + +`preferredLanguage` → A string indicating the preferred language/locale for the +user. When logging in +[`pam_systemd`](https://www.freedesktop.org/software/systemd/man/pam_systemd.html) +will automatically initialize the `$LANG` environment variable from this +string. The string hence should be in a format compatible with this environment +variable, for example: `de_DE.UTF8`. + +`niceLevel` → An integer value in the range -20…19. When logging in +[`pam_systemd`](https://www.freedesktop.org/software/systemd/man/pam_systemd.html) +will automatically initialize the login process' nice level to this value with, +which is then inherited by all the user's processes, see +[`setpriority()`](http://man7.org/linux/man-pages/man2/setpriority.2.html) for +more information. + +`resourceLimits` → An object, where each key refers to a Linux resource limit +(such as `RLIMIT_NOFILE` and similar). Their values should be an object with +two keys `cur` and `max` for the soft and hard resource limit. When logging in +[`pam_systemd`](https://www.freedesktop.org/software/systemd/man/pam_systemd.html) +will automatically initialize the login process' resource limits to these +values, which is then inherited by all the user's processes, see +[`setrlimit()`](http://man7.org/linux/man-pages/man2/setrlimit.2.html) for more +information. + +`locked` → A boolean value. If true the user account is locked, the user may +not log in. If this field is missing it should be assumed to be false, +i.e. logins are permitted. This field corresponds to the `sp_expire` field of +`struct spwd` (i.e. the `/etc/shadow` data for a user) being set to zero or +one. + +`notBeforeUSec` → An unsigned 64bit integer value, indicating a time in µs since +the UNIX epoch (1970) before which the record should be considered invalid for +the purpose of logging in. + +`notAfterUSec` → Similar, but indicates the point in time *after* which logins +shall not be permitted anymore. This corresponds to the `sp_expire` field of +`struct spwd`, when it is set to a value larger than one, but provides finer +granularity. + +`storage` → A string, one of `classic`, `luks`, `directory`, `subvolume`, +`fscrypt`, `cifs`. Indicates the storage mechanism for the user's home +directory. If `classic` the home directory is a plain directory as in classic +UNIX. When `directory`, the home directory is a regular directory, but the +`~/.identity` file in it contains the user's user record, so that the directory +is self-contained. Similar, `subvolume` is a `btrfs` subvolume that also +contains a `~/.identity` user record; `fscrypt` is an `fscrypt`-encrypted +directory, also containing the `~/.identity` user record; `luks` is a per-user +LUKS volume that is mounted as home directory, and `cifs` a home directory +mounted from a Windows File Share. The five latter types are primarily used by +`systemd-homed` when managing home directories, but may be used if other +managers are used too. If this is not set `classic` is the implied default. + +`diskSize` → An unsigned 64bit integer, indicating the intended home directory +disk space in bytes to assign to the user. Depending on the selected storage +type this might be implement differently: for `luks` this is the intended size +of the file system and LUKS volume, while for the others this likely translates +to classic file system quota settings. + +`diskSizeRelative` → Similar to `diskSize` but takes a relative value, but +specifies a fraction of the available disk space on the selected storage medium +to assign to the user. This unsigned integer value is normalized to 2^32 = +100%. + +`skeletonDirectory` → Takes a string with the absolute path to the skeleton +directory to populate a new home directory from. This is only used when a home +directory is first created, and defaults to `/etc/skel` if not defined. + +`accessMode` → Takes an unsigned integer in the range 0…511 indicating the UNIX +access mask for the home directory when it is first created. + +`tasksMax` → Takes an unsigned 64bit integer indicating the maximum number of +tasks the user may start in parallel during system runtime. This value is +enforced on all tasks (i.e. processes and threads) the user starts or that are +forked off these processes regardless if the change user identity (for example +by setuid binaries/`su`/`sudo` and +similar). [`systemd-logind.service`](https://www.freedesktop.org/software/systemd/man/systemd-logind.service.html) +enforces this by setting the `TasksMax` slice property for the user's slice +`user-$UID.slice`. + +`memoryHigh`/`memoryMax` → These take unsigned 64bit integers indicating upper +memory limits for all processes of the user (plus all processes forked off them +that might have changed user identity), in bytes. Enforced by +[`systemd-logind.service`](https://www.freedesktop.org/software/systemd/man/systemd-logind.service.html), +similar to `tasksMax`. + +`cpuWeight`/`ioWeight` → These take unsigned integers in the range 1…10000 +(defaults to 100) and configure the CPU and IO scheduling weights for the +user's processes as a whole. Also enforced by +[`systemd-logind.service`](https://www.freedesktop.org/software/systemd/man/systemd-logind.service.html), +similar to `tasksMax`, `memoryHigh` and `memoryMax`. + +`mountNoDevices`/`mountNoSuid`/`mountNoExecute` → Three booleans that control +the `nodev`, `nosuid`, `noexec` mount flags of the user's home +directories. Note that these booleans are only honored if the home directory +is managed by a subsystem such as `systemd-homed.service` that automatically +mounts home directories on login. + +`cifsDomain` → A string indicating the Windows File Sharing domain (CIFS) to +use. This is generally useful, but particularly when `cifs` is used as storage +mechanism for the user's home directory, see above. + +`cifsUserName` → A string indicating the Windows File Sharing user name (CIFS) +to associate this user record with. This is generally useful, but particularly +useful when `cifs` is used as storage mechanism for the user's home directory, +see above. + +`cifsService` → A string indicating the Windows File Share service (CIFS) to +mount as home directory of the user on login. + +`imagePath` → A string with an absolute file system path to the file, directory +or block device to use for storage backing the home directory. If the `luks` +storage is used this refers to the loopback file or block device node to store +the LUKS volume on. For `fscrypt`, `directory`, `subvolume` this refers to the +directory to bind mount as home directory on login. Not defined for `classic` +or `cifs`. + +`homeDirectory` → A string with an absolute file system path to the home +directory. This is where the image indicated in `imagePath` is mounted to on +login and thus indicates the application facing home directory while the home +directory is active, and is what the user's `$HOME` environment variable is set +to during log-in. It corresponds to the `pw_dir` field of `struct passwd`. + +`uid` → An unsigned integer in the range 0…4294967295: the numeric UNIX user ID (UID) to +use for the user. This corresponds to the `pw_uid` field of `struct passwd`. + +`gid` → An unsigned integer in the range 0…4294967295: the numeric UNIX group +ID (GID) to use for the user. This corresponds to the `pw_gid` field of +`struct passwd`. + +`memberOf` → An array of strings, each indicating a UNIX group this user shall +be a member of. The listed strings must be valid group names, but it is not +required that all groups listed exist in all contexts: any entry for which no +group exists should be silently ignored. + +`fileSystemType` → A string, one of `ext4`, `xfs`, `btrfs` (possibly others) to +use as file system for the user's home directory. This is primarily relevant +when the storage mechanism used is `luks` as a file system to use inside the +LUKS container must be selected. + +`partitionUuid` → A string containing a lower-case, text-formatted UUID, referencing +the GPT partition UUID the home directory is located in. This is primarily +relevant when the storage mechanism used is `luks`. + +`luksUuid` → A string containing a lower-case, text-formatted UUID, referencing +the LUKS volume UUID the home directory is located in. This is primarily +relevant when the storage mechanism used is `luks`. + +`fileSystemUuid` → A string containing a lower-case, text-formatted UUID, +referencing the file system UUID the home directory is located in. This is +primarily relevant when the storage mechanism used is `luks`. + +`luksDiscard` → A boolean. If true and `luks` storage is used controls whether +the loopback block devices, LUKS and the file system on top shall be used in +`discard` mode, i.e. erased sectors should always be returned to the underlying +storage. If false and `luks` storage is used turns this behavior off. In +addition, depending on this setting an `FITRIM` or `fallocate()` operation is +executed to make sure the image matches the selected option. + +`luksCipher` → A string, indicating the cipher to use for the LUKS storage mechanism. + +`luksCipherMode` → A string, selecting the cipher mode to use for the LUKS storage mechanism. + +`luksVolumeKeySize` → An unsigned integer, indicating the volume key length in +bytes to use for the LUKS storage mechanism. + +`luksPbkdfHashAlgorithm` → A string, selecting the hash algorithm to use for +the PBKDF operation for the LUKS storage mechanism. + +`luksPbkdfType` → A string, indicating the PBKDF type to use for the LUKS storage mechanism. + +`luksPbkdfTimeCostUSec` → An unsigned 64bit integer, indicating the intended +time cost for the PBKDF operation, when the LUKS storage mechanism is used, in +µs. + +`luksPbkdfMemoryCost` → An unsigned 64bit integer, indicating the intended +memory cost for the PBKDF operation, when LUKS storage is used, in bytes. + +`luksPbkdfParallelThreads` → An unsigned 64bit integer, indicating the intended +required parallel threads for the PBKDF operation, when LUKS storage is used. + +`service` → A string declaring the service that defines or manages this user +record. It is recommended to use reverse domain name notation for this. For +example, if `systemd-homed` manages a user a string of `io.systemd.Home` is +used for this. + +`rateLimitIntervalUSec` → An unsigned 64bit integer that configures the +authentication rate limiting enforced on the user account. This specifies a +timer interval (in µs) within which to count authentication attempts. When the +counter goes above the value configured n `rateLimitIntervalBurst` log-ins are +temporarily refused until the interval passes. + +`rateLimitIntervalBurst` → An unsigned 64bit integer, closely related to +`rateLimitIntervalUSec`, that puts a limit on authentication attempts within +the configured time interval. + +`enforcePasswordPolicy` → A boolean. Configures whether to enforce the system's +password policy when creating the home directory for the user or changing the +user's password. By default the policy is enforced, but if this field is false +it is bypassed. + +`autoLogin` → A boolean. If true the user record is marked as suitable for +auto-login. Systems are supposed to automatically log in a user marked this way +during boot, if there's exactly one user on it defined this way. + +`stopDelayUSec` → An unsigned 64bit integer, indicating the time in µs the +per-user service manager is kept around after the user fully logged out. This +value is honored by +[`systemd-logind.service`](https://www.freedesktop.org/software/systemd/man/systemd-logind.service.html). If +set to zero the per-user service manager is immediately terminated when the +user logs out, and longer values optimize high-frequency log-ins as the +necessary work to set up and tear down a log-in is reduced if the service +manager stays running. + +`killProcesses` → A boolean. If true all processes of the user are +automatically killed when the user logs out. This is enforced by +[`systemd-logind.service`](https://www.freedesktop.org/software/systemd/man/systemd-logind.service.html). If +false any processes left around when the user logs out are left running. + +`passwordChangeMinUSec`/`passwordChangeMaxUSec` → An unsigned 64bit integer, +encoding how much time has to pass at least/at most between password changes of +the user. This corresponds with the `sp_min` and `sp_max` fields of `struct +spwd` (i.e. the `/etc/shadow` entries of the user), but offers finer +granularity. + +`passwordChangeWarnUSec` → An unsigned 64bit integer, encoding how much time to +warn the user before their password expires, in µs. This corresponds with the +`sp_warn` field of `struct spwd`. + +`passwordChangeInactiveUSec` → An unsigned 64bit integer, encoding how much +time has to pass after the password expired that the account is +deactivated. This corresponds with the `sp_inact` field of `struct spwd`. + +`passwordChangeNow` → A boolean. If true the user has to change their password +on next login. This corresponds with the `sp_lstchg` field of `struct spwd` +being set to zero. + +`pkcs11TokenUri` → An array of strings, each with an RFC 7512 compliant PKCS#11 +URI referring to security token (or smart card) of some form, that shall be +associated with the user and may be used for authentication. The URI is used to +search for an X.509 certificate and associated private key that may be used to +decrypt an encrypted secret key that is used to unlock the user's account (see +below). It's undefined how precise the URI is: during log-in it is tested +against all plugged in security tokens and if there's exactly one matching +private key found with it it is used. + +`privileged` → An object, which contains the fields of he `privileged` section +of the user record, see below. + +`perMachine` → An array of objects, which contain the `perMachine` section of +the user record, and thus fields to apply on specific systems only, see below. + +`binding` → An object, keyed by machine IDs formatted as strings, pointing +to objects that contain the `binding` section of the user record, +i.e. additional fields that bind the user record to a specific machine, see +below. + +`status` → An object, keyed by machine IDs formatted as strings, pointing to +objects that contain the `status` section of the user record, i.e. additional +runtime fields that expose the current status of the user record on a specific +system, see below. + +`signature` → An array of objects, which contain cryptographic signatures of +the user record, i.e. the fields of the `signature` section of the user record, +see below. + +`secret` → An object, which contains the fields of the `secret` section of the +user record, see below. + +## Fields in the `privileged` section + +As mentioned, the `privileged` section is encoded in a sub-object of the user +record top-level object, in the `privileged` field. Any data included in this +object shall only be visible to the administrator and the user themselves, and +be suppressed implicitly when other users get access to a user record. It thus +takes the role of the `/etc/shadow` records for each user, which has similarly +restrictive access semantics. The following fields are currently defined: + +`passwordHint` → A user-selected password hint in free-form text. This should +be a string like "What's the name of your first pet?", but is entirely for the +user to choose. + +`hashPassword` → An array of strings, each containing a hashed UNIX password +string, in the format +[`crypt(3)`](http://man7.org/linux/man-pages/man3/crypt.3.html) generates. This +corresponds with `sp_pwdp` field of `struct spwd` (and in a way the `pw_passwd` +field of `struct passwd`). + +`sshAuthorizedKeys` → An array of strings, each listing an SSH public key that +is authorized to access the account. The strings should follow the same format +as the lines in the traditional `~/.ssh/authorized_key` file. + +`pkcs11EncryptedKey` → An array of objects. Each element of the array should be +an object consisting of three string fields: `uri` shall contain a PKCS#11 +security token URI, `data` shall contain a Base64 encoded encrypted key and +`hashedPassword` shall contain a UNIX password hash to test the key +against. Authenticating with a security token against this account shall work +as follows: the encrypted secret key is converted from its Base64 +representation into binary, then decrypted with the PKCS#11 `C_Decrypt()` +function of the PKCS#11 module referenced by the specified URI, using the +private key found on the same token. The resulting decrypted key is then +Base64-encoded and tested against the specified UNIX hashed password. The +Base64-enceded decrypted key may also be used to unlock further resources +during log-in, for example the LUKS or `fscrypt` storage backend. It is +generally recommended that for each entry in `pkcs11EncryptedKey` there's also +a matching one in `pkcs11TokenUri` and vice versa, with the same URI, appearing +in the same order, but this should not be required by applications processing +user records. + +## Fields in the `perMachine` section + +As mentioned, the `perMachine` section contains settings that shall apply to +specific systems only. This is primarily interesting for resource management +properties as they tend to require a per-system focus, however they may be used +for other purposes too. + +The `perMachine` field in the top-level object is an array of objects. When +processing the user record first the various fields on the top-level object +should be used. Then this array should be iterated in order, and the various +settings be applied that match either the indicated machine ID or host +name. There may be multiple array entries that match a specific system, in +which case all the object's setting should be applied. If the same option is +set in the top-level object as in a per-machine object the latter wins and +entirely undoes the setting in the top-level object (i.e. no merging of +properties that are arrays themselves is done). If the same option is set in +multiple per-machine objects the one specified later in the array wins (and +here too no merging of individual fields is done, the later field always wins +in full). + +The following fields are defined in this section: + +`matchMachineId` → An array of strings with each a formatted 128bit ID in +hex. If any of the specified IDs match the system's local machine ID +(i.e. matches `/etc/machine-id`) the fields in this object are honored. + +`matchHostname` → An array of string with a each a valid hostname. If any of +the specified hostnames match the system's local hostname, the fields in this +object are honored. If both `matchHostname` and `matchMachineId` are used +within the same array entry, the object is honored when either match succeeds, +i.e. the two match types are combined in OR, not in AND. + +These two are the only two fields specific to this section. All other fields +that may be used in this section are identical to the equally named ones in the +`regular` section (i.e. at the top-level object). Specifically, these are: + +`iconName`, `location`, `shell`, `umask`, `environment`, `timeZone`, +`preferredLanguage`, `niceLevel`, `resourceLimits`, `locked`, `notBeforeUSec`, +`notAfterUSec`, `storage`, `diskSize`, `diskSizeRelative`, `skeletonDirectory`, +`accessMode`, `tasksMax`, `memoryHigh`, `memoryMax`, `cpuWeight`, `ioWeight`, +`mountNoDevices`, `mountNoSuid`, `mountNoExecute`, `cifsDomain`, +`cifsUserName`, `cifsService`, `imagePath`, `uid`, `gid`, `memberOf`, +`fileSystemType`, `partitionUuid`, `luksUuid`, `fileSystemUuid`, `luksDiscard`, +`luksCipher`, `luksCipherMode`, `luksVolumeKeySize`, `luksPbkdfHashAlgorithm`, +`luksPbkdfType`, `luksPbkdfTimeCostUSec`, `luksPbkdfMemoryCost`, +`luksPbkdfParallelThreads`, `rateLimitIntervalUSec`, `rateLimitBurst`, +`enforcePasswordPolicy`, `autoLogin`, `stopDelayUSec`, `killProcesses`, +`passwordChangeMinUSec`, `passwordChangeMaxUSec`, `passwordChangeWarnUSec`, +`passwordChangeInactiveUSec`, `passwordChangeNow`, `pkcs11TokenUri`. + +## Fields in the `binding` section + +As mentioned, the `binding` section contains additional fields about the user +record, that bind it to the local system. These fields are generally used by a +local user manager (such as `systemd-homed.service`) to add in fields that make +sense in a local context but not necessarily in a global one. For example, a +user record that contains no `uid` field in the regular section is likely +extended with one in the `binding` section to assign a local UID if no global +UID is defined. + +All fields in the `binding` section only make sense in a local context and are +suppressed when the user record is ported between systems. The `binding` section +is generally persisted on the system but not in the home directories themselves +and the home directory is supposed to be fully portable and thus not contain +the information that `binding` is supposed to contain that binds the portable +record to a specific system. + +The `binding` sub-object on the top-level user record object is keyed by the +machine ID the binding is intended for, which point to an object with the +fields of the bindings. These fields generally match fields that may also be +defined in the `regular` and `perMachine` sections, however override +both. Usually, the `binding` value should not contain settings different from +those set via `regular` or `perMachine`, however this might happen if some +settings are not supported locally (think: `fscrypt` is recorded as intended +storage mechanism in the `regular` section, but the local kernel does not +support `fscrypt`, hence `directory` was chosen as implicit fallback), or have +been changed in the `regular` section through updates (e.g. a home directory +was created with `luks` as storage mechanism but later the user record was +updated to prefer `subvolume`, which however doesn't change the actual storage +used already which is pinned in the `binding` section). + +The following fields are defined in the `binding` section. They all have an +identical format and override their equally named counterparts in the `regular` +and `perMachine` sections: + +`imagePath`, `homeDirectory`, `partitionUuid`, `luksUuid`, `fileSystemUuid`, +`uid`, `gid`, `storage`, `fileSystemType`, `luksCipher`, `luksCipherMode`, +`luksVolumeKeySize`. + +## Fields in the `status` section + +As mentioned, the `status` section contains additional fields about the user +record that are exclusively acquired during runtime, and that expose runtime +metrics of the user and similar metadata that shall not be persisted but are +only acquired "on-the-fly" when requested. + +This section is arranged similarly to the `binding` section: the `status` +sub-object of the top-level user record object is keyed by the machine ID, +which points to the object with the fields defined here. The following fields +are defined: + +`diskUsage` → An unsigned 64bit integer. The currently used disk space of the +home directory in bytes. This value might be determined in different ways, +depending on the selected storage mechanism. For LUKS storage this is the file +size of the loopback file or block device size. For the +directory/subvolume/fscrypt storage this is the current disk space used as +reported by the file system quota subsystem. + +`diskFree` → An unsigned 64bit integer, denoting the number of "free" bytes in +the disk space allotment, i.e. usually the difference between the disk size as +reported by `diskSize` and the used already as reported in `diskFree`, but +possibly skewed by metadata sizes, disk compression and similar. + +`diskSize` → An unsigned 64bit integer, denoting the disk space currently +allotted to the user, in bytes. Depending on the storage mechanism this can mean +different things (see above). In contrast to the top-level field of the same +(or the one in the `perMachine` section), this field reports the current size +allotted to the user, not the intended one. The values may differ when user +records are updated without the home directory being re-sized. + +`diskCeiling`/`diskFloor` → Unsigned 64bit integers indicating upper and lower +bounds when changing the `diskSize` value, in bytes. These values are typically +derived from the underlying data storage, and indicate in which range the home +directory may be re-sized in, i.e. in which sensible range the `diskSize` value +should be kept. + +`state` → A string indicating the current state of the home directory. The +precise set of values exposed here are up to the service managing the home +directory to define (i.e. are up to the service identified with the `service` +field below). However, it is recommended to stick to a basic vocabulary here: +`inactive` for a home directory currently not mounted, `absent` for a home +directory that cannot be mounted currently because it does not exist on the +local system, `active` for a home directory that is currently mounted and +accessible. + +`service` → A string identifying the service that manages this user record. For +example `systemd-homed.service` sets this to `io.systemd.Home` to all user +records it manages. This is particularly relevant to define clearly the context +in which `state` lives, see above. Note that this field also exists on the +top-level object (i.e. in the `regular` section), which it overrides. The +`regular` field should be used if conceptually the user record can only be +managed by the specified service, and this `status` field if it can +conceptually be managed by different managers, but currently is managed by the +specified one. + +`signedLocally` → A boolean. If true indicates that the user record is signed +by a public key for which the private key is available locally. This means that +the user record may be modified locally as it can be re-signed with the private +key. If false indicates that the user record is signed by a public key +recognized by the local manager but whose private key is not available +locally. This means the user record cannot be modified locally as it couldn't +be signed afterwards. + +`goodAuthenticationCounter` → An unsigned 64bit integer. This counter is +increased by one on every successful authentication attempt, i.e. an +authentication attempt where a security token of some form was presented and it +was correct. + +`badAuthenticationCounter` → An unsigned 64bit integer. This counter is +increased by one on every unsuccessfully authentication attempt, i.e. an +authentication attempt where a security token of some form was presented and it +was incorrect. + +`lastGoodAuthenticationUSec` → An unsigned 64bit integer, indicating the time +of the last successful authentication attempt in µs since the UNIX epoch (1970). + +`lastBadAuthenticationUSec` → Similar, but the timestamp of the last +unsuccessfully authentication attempt. + +`rateLimitBeginUSec` → An unsigned 64bit integer: the µs timestamp since the +UNIX epoch (1970) where the most recent rate limiting interval has been +started, as configured with `rateLimitIntervalUSec`. + +`rateLimitCount` → An unsigned 64bit integer, counting the authentication +attempts in the current rate limiting interval, see above. If this counter +grows beyond the value configured in `rateLimitBurst` authentication attempts +are temporarily refused. + +`removable` → A boolean value. If true the manager of this user record +determined the home directory being on removable media. If false it was +determined the home directory is in internal built-in media. (This is used by +`systemd-logind.service` to automatically pick the right default value for +`stopDelayUSec` if the field is not explicitly specified: for home directories +on removable media the delay is selected very low to minimize the chance the +home directory remains in unclean state if the storage device is removed from +the system by the user). + +## Fields in the `signature` section + +As mentioned, the `signature` section of the user record may contain one or +more cryptographic signatures of the user record. Like all others, this section +is optional, and only used when cryptographic validation of user records shall +be used. Specifically, all user records managed by `systemd-homed.service` will +carry such signatures and the service refuses managing user records that come +without signature or with signatures not recognized by any locally defined +public key. + +The `signature` field in the top-level user record object is an array of +objects. Each object encapsulates one signature and has two fields: `data` and +`key` (both are strings). The `data` field contains the actual signature, +encoded in base64, the `key` field contains a copy of the public key whose +private key was used to make the signature, in PEM format. Currently only +signatures with Ed25519 keys are defined. + +Before signing the user record should be brought into "normalized" form, +i.e. the keys in all objects should be sorted alphabetically. All redundant +white-space and newlines should be removed and the JSON text then signed. + +The signatures only cover the `regular`, `perMachine` and `privileged` sections +of the user records, all other sections (include `signature` itself), are +removed before the signature is calculated. + +Rationale for signing and threat model: while a multi-user operating system +like Linux strives for being sufficiently secure even after a user acquired a +local login session reality tells us this is not the case. Hence it is +essential to restrict carefully which users may gain access to a system and +which ones shall not. A minimal level of trust must be established between +system, user record and the user themselves before a log-in request may be +permitted. In particular if the home directory is provided in its own LUKS2 +encapsulated file system it is essential this trust is established before the +user logs in (and hence the file system mounted), since file system +implementations on Linux are well known to be relatively vulnerable to rogue +disk images. User records and home directories in many context are expected to +be something shareable between multiple systems, and the transfer between them +might not happen via exclusively trusted channels. Hence it's essential that +the user record is not manipulated between uses. Finally, resource management +(which may be done by the various fields of the user record) is security +sensitive, since it should forcefully lock the user into the assigned resource +usage and not allow them to use more. The requirement of being able to trust +the user record data combined with the potential transfer over untrusted +channels suggest a cryptographic signature mechanism where only user records +signed by a recognized key are permitted to log in locally. + +Note that other mechanisms for establishing sufficient trust exist too, and are +perfectly valid as well. For example, systems like LDAP/ActiveDirectory +generally insist on user record transfer from trusted servers via encrypted TLS +channels only. Or traditional UNIX users created locally in `/etc/passwd` never +exist outside of the local trusted system, hence transfer and trust in the +source are not an issue. The major benefit of operating with signed user +records is that they are self-sufficiently trusted, not relying on a secure +channel for transfer, and thus being compatible with a more distributed model +of home directory transfer, including on USB sticks and such. + +## Fields in the `secret` section + +As mentioned, the `secret` section of the user record should never be persisted +nor transferred across machines. It is only defined in short-lived operations, +for example when a user record is first created or registered, as the secret +key data needs to be available to derive encryption keys from and similar. + +The `secret` field of the top-level user record contains the following fields: + +`password` → an array of strings, each containing a plain text password. + +`pkcs11Pin` → an array of strings, each containing a plain text PIN, suitable +for unlocking PKCS#11 security tokens that require that. + +`pkcs11ProtectedAuthenticationPathPermitted` → a boolean. If set to true allows +the receiver to use the PKCS#11 "protected authentication path" (i.e. a +physical button/touch element on the security token) for authenticating the +user. If false or unset authentication this way shall not be attempted. + +## Mapping to `struct passwd` and `struct spwd` + +When mapping classic UNIX user records (i.e. `struct passwd` and `struct spwd`) +to JSON user records the following mappings should be applied: + +| Structure | Field | Section | Field | Condition | +|-----------------|-------------|--------------|------------------------------|----------------------------| +| `struct passwd` | `pw_name` | `regular` | `userName` | | +| `struct passwd` | `pw_passwd` | `privileged` | `password` | (See notes below) | +| `struct passwd` | `pw_uid` | `regular` | `uid` | | +| `struct passwd` | `pw_gid` | `regular` | `gid` | | +| `struct passwd` | `pw_gecos` | `regular` | `realName` | | +| `struct passwd` | `pw_dir` | `regular` | `homeDirectory` | | +| `struct passwd` | `pw_shell` | `regular` | `shell` | | +| `struct spwd` | `sp_namp` | `regular` | `userName` | | +| `struct spwd` | `sp_pwdp` | `privileged` | `password` | (See notes below) | +| `struct spwd` | `sp_lstchg` | `regular` | `lastPasswordChangeUSec` | (if `sp_lstchg` > 0) | +| `struct spwd` | `sp_lstchg` | `regular` | `passwordChangeNow` | (if `sp_lstchg` == 0) | +| `struct spwd` | `sp_min` | `regular` | `passwordChangeMinUSec` | | +| `struct spwd` | `sp_max` | `regular` | `passwordChangeMaxUSec` | | +| `struct spwd` | `sp_warn` | `regular` | `passwordChangeWarnUSec` | | +| `struct spwd` | `sp_inact` | `regular` | `passwordChangeInactiveUSec` | | +| `struct spwd` | `sp_expire` | `regular` | `locked` | (if `sp_expire` in [0, 1]) | +| `struct spwd` | `sp_expire` | `regular` | `notAfterUSec` | (if `sp_expire` > 1) | + +At this time almost all Linux machines employ shadow passwords, thus the +`pw_passwd` field in `struct passwd` is set to `"x"`, and the actual password +is stored in the shadow entry `struct spwd`'s field `sp_pwdp`. + +## Extending These Records + +User records following this specifications are supposed to be extendable for +various applications. In general, subsystems are free to introduce their own +keys, as long as: + +* Care should be taken to place the keys in the right section, i.e. the most + appropriate for the data field. + +* Care should be taken to avoid namespace clashes. Please prefix your fields + with a short identifier of your project to avoid ambiguities and + incompatibilities. + +* This specification is supposed to be a living specification. If you need + additional fields, please consider submitting them upstream for inclusion in + this specification. If they are reasonably universally useful, it would be + best to list them here. + +## Examples + +The shortest valid user record looks like this: + +```json +{ + "userName" : "u" +} +``` + +A reasonable user record for a system user might look like this: + +```json +{ + "userName" : "httpd", + "uid" : 473, + "gid" : 473, + "disposition" : "system", + "locked" : true +} +``` + +A fully featured user record associated with a home directory managed by +`systemd-homed.service` might look like this: + +```json +{ + "autoLogin" : true, + "binding" : { + "15e19cf24e004b949ddaac60c74aa165" : { + "fileSystemType" : "ext4", + "fileSystemUuid" : "758e88c8-5851-4a2a-b88f-e7474279c111", + "gid" : 60232, + "homeDirectory" : "/home/grobie", + "imagePath" : "/home/grobie.home", + "luksCipher" : "aes", + "luksCipherMode" : "xts-plain64", + "luksUuid" : "e63581ba-79fb-4226-b9de-1888393f7573", + "luksVolumeKeySize" : 32, + "partitionUuid" : "41f9ce04-c827-4b74-a981-c669f93eb4dc", + "storage" : "luks", + "uid" : 60232 + } + }, + "disposition" : "regular", + "enforcePasswordPolicy" : false, + "lastChangeUSec" : 1565950024279735, + "memberOf" : [ + "wheel" + ], + "privileged" : { + "hashedPassword" : [ + "$6$WHBKvAFFT9jKPA4k$OPY4D4TczKN/jOnJzy54DDuOOagCcvxxybrwMbe1SVdm.Bbr.zOmBdATp.QrwZmvqyr8/SafbbQu.QZ2rRvDs/" + ] + }, + "signature" : [ + { + "data" : "LU/HeVrPZSzi3MJ0PVHwD5m/xf51XDYCrSpbDRNBdtF4fDVhrN0t2I2OqH/1yXiBidXlV0ptMuQVq8KVICdEDw==", + "key" : "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA/QT6kQWOAMhDJf56jBmszEQQpJHqDsGDMZOdiptBgRk=\n-----END PUBLIC KEY-----\n" + } + ], + "userName" : "grobie", + "status" : { + "15e19cf24e004b949ddaac60c74aa165" : { + "goodAuthenticationCounter" : 16, + "lastGoodAuthenticationUSec" : 1566309343044322, + "rateLimitBeginUSec" : 1566309342340723, + "rateLimitCount" : 1, + "state" : "inactive", + "service" : "io.systemd.Home", + "diskSize" : 161118667776, + "diskCeiling" : 190371729408, + "diskFloor" : 5242880, + "signedLocally" : true + } + } +} +``` + +When `systemd-homed.service` manages a home directory it will also include a +version of the user record in the home directory itself in the `~/.identity` +file. This version lacks the `binding` and `status` sections which are used for +local management of the user, but are not intended to be portable between +systems. It would hence look like this: + +```json +{ + "autoLogin" : true, + "disposition" : "regular", + "enforcePasswordPolicy" : false, + "lastChangeUSec" : 1565950024279735, + "memberOf" : [ + "wheel" + ], + "privileged" : { + "hashedPassword" : [ + "$6$WHBKvAFFT9jKPA4k$OPY4D4TczKN/jOnJzy54DDuOOagCcvxxybrwMbe1SVdm.Bbr.zOmBdATp.QrwZmvqyr8/SafbbQu.QZ2rRvDs/" + ] + }, + "signature" : [ + { + "data" : "LU/HeVrPZSzi3MJ0PVHwD5m/xf51XDYCrSpbDRNBdtF4fDVhrN0t2I2OqH/1yXiBidXlV0ptMuQVq8KVICdEDw==", + "key" : "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA/QT6kQWOAMhDJf56jBmszEQQpJHqDsGDMZOdiptBgRk=\n-----END PUBLIC KEY-----\n" + } + ], + "userName" : "grobie", +} +``` diff --git a/docs/_config.yml b/docs/_config.yml index ee845eec8..925b4adb1 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1 +1,9 @@ -theme: jekyll-theme-primer +# Site settings +title: systemd +baseurl: "" # the subpath of your site, e.g. /blog/ +url: "http://systemd.io" # the base hostname & protocol for your site + +permalink: /:title/ + +# Build settings +markdown: kramdown diff --git a/docs/_data/extra_pages.json b/docs/_data/extra_pages.json new file mode 100644 index 000000000..5ede56c6f --- /dev/null +++ b/docs/_data/extra_pages.json @@ -0,0 +1,10 @@ +[ + { "category": "Project", "title": "Brand", "url": "https://brand.systemd.io/" }, + { "category": "Project", "title": "Releases", "url": "https://github.com/systemd/systemd/releases" }, + { "category": "Project", "title": "GitHub Project Page", "url": "https://github.com/systemd/systemd" }, + { "category": "Project", "title": "Issues", "url": "https://github.com/systemd/systemd/issues" }, + { "category": "Project", "title": "Pull Requests", "url": "https://github.com/systemd/systemd/pulls" }, + { "category": "Project", "title": "Mailing List", "url": "https://lists.freedesktop.org/mailman/listinfo/systemd-devel" }, + { "category": "Manual Pages", "title": "Index", "url": "https://www.freedesktop.org/software/systemd/man/" }, + { "category": "Manual Pages", "title": "Directives", "url": "https://www.freedesktop.org/software/systemd/man/systemd.directives.html" } +] diff --git a/docs/_includes/footer.html b/docs/_includes/footer.html new file mode 100644 index 000000000..95289732b --- /dev/null +++ b/docs/_includes/footer.html @@ -0,0 +1,5 @@ + diff --git a/docs/_includes/head.html b/docs/_includes/head.html new file mode 100644 index 000000000..3ff4bbe0b --- /dev/null +++ b/docs/_includes/head.html @@ -0,0 +1,16 @@ + + + + + + + {% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %} + + + + + + + + + diff --git a/docs/_includes/header.html b/docs/_includes/header.html new file mode 100644 index 000000000..4e885fbe7 --- /dev/null +++ b/docs/_includes/header.html @@ -0,0 +1,11 @@ + diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html new file mode 100644 index 000000000..672aa0cd5 --- /dev/null +++ b/docs/_layouts/default.html @@ -0,0 +1,18 @@ + + + + {% include head.html %} + + + + {% include header.html %} + +
+ {{ content }} +
+ + {% include footer.html %} + + + + diff --git a/docs/assets/page-logo.svg b/docs/assets/page-logo.svg new file mode 100644 index 000000000..e59c88af3 --- /dev/null +++ b/docs/assets/page-logo.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/docs/favicon.png b/docs/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..f4b5cc146a8c07b679e75df01a55a10f8a3b7c8e GIT binary patch literal 394 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq!<_&**#qx zLo9laPTuHsI6$OrfA!@hjX?{KCiyxPDVkge7r0x)Z7nK)Fi=LOhI#v=3Ev9}Ke1~0 z`I(lzRLZ#ZVlUsqrLnh8$o@Hg`scsH#~*fC^u0d1yja=b`2oeNlNvpxb>E-L{53ba zaVN_x(Zo}cg)vWV2?t&{-SAHS!Ph7PXTh8h#M z^Uo|U%DwY!sFwOr_;G__e6-n01I7dL-#(t}JLS$?^{dt1!))6sgUG2l;RbA*f81QV z;YvWFlbuwv=EFb#ByDGZ{%aDexkj70L*vEFwc2G*{-4)qJkvDa!(gSWzrl(&kw+GWAJqKb6Mw<&;$S + + + + + + + + + diff --git a/docs/fonts/heebo-bold.woff b/docs/fonts/heebo-bold.woff new file mode 100644 index 0000000000000000000000000000000000000000..1e45115e1e32079307c9e38ea54a1755febfcd34 GIT binary patch literal 42844 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≷bl|jlJ8;tIi~Hu2 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
UHX7yKL93D`ecI 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 F001gxDZc;! literal 0 HcmV?d00001 diff --git a/docs/fonts/heebo-regular.woff b/docs/fonts/heebo-regular.woff new file mode 100644 index 0000000000000000000000000000000000000000..484eae455569fb5a74897f312a31ec8183a4b025 GIT binary patch literal 42672 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