1use std::{
4 fs::{File, Permissions, create_dir_all, read_dir, set_permissions, write},
5 io::Write,
6 os::{linux::fs::MetadataExt, unix::fs::PermissionsExt},
7 path::{Path, PathBuf},
8 process::{Child, Command},
9 str::FromStr,
10 thread,
11 time,
12};
13
14use change_user_run::{create_users, get_command};
15use log::debug;
16#[cfg(feature = "nethsm")]
17use nethsm::{FullCredentials, UserId};
18use signstar_common::system_user::get_home_base_dir_path;
19#[cfg(feature = "nethsm")]
20use signstar_crypto::AdministrativeSecretHandling;
21#[cfg(feature = "nethsm")]
22use signstar_crypto::passphrase::Passphrase;
23use tempfile::NamedTempFile;
24
25use crate::config::{Config, ConfigSystemUserIds, MappingAuthorizedKeyEntry};
26#[cfg(feature = "nethsm")]
27use crate::{admin_credentials::AdminCredentials, nethsm::NetHsmAdminCredentials};
28#[cfg(any(feature = "nethsm", feature = "yubihsm2"))]
30pub mod impl_any {
31 use super::*;
32 use crate::config::UserBackendConnectionFilter;
33
34 impl SystemUserConfig {
35 pub fn apply(&self, config: &Config) -> Result<(), crate::Error> {
41 if self.create_secrets {
42 let user_backend_connections =
43 config.user_backend_connections(&[UserBackendConnectionFilter::NonAdmin]);
44
45 for user_backend_connection in user_backend_connections {
46 user_backend_connection.create_non_admin_backend_user_secrets()?;
47 }
48 }
49
50 if self.create_ssh_authorized_keys {
51 let user_backend_connections =
52 config.user_backend_connections(&[UserBackendConnectionFilter::NonAdmin]);
53 for user_backend_connection in user_backend_connections {
54 user_backend_connection.write_authorized_key_entry()?;
55 }
56
57 for mapping in config.system().mappings() {
58 mapping.write_authorized_key_entry()?;
59 }
60 }
61
62 Ok(())
63 }
64 }
65}
66
67#[cfg(not(any(feature = "nethsm", feature = "yubihsm2")))]
69mod impl_none {
70 use super::*;
71
72 impl SystemUserConfig {
73 pub fn apply(&self, config: &Config) -> Result<(), crate::Error> {
83 if self.create_ssh_authorized_keys {
84 for mapping in config.system().mappings() {
85 mapping.write_authorized_key_entry()?;
86 }
87 }
88
89 Ok(())
90 }
91 }
92}
93
94const NO_BACKEND_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT: &[u8] =
99 include_bytes!("../../fixtures/config/no_backend/admin-plaintext-non-admin-plaintext.yaml");
100
101const NO_BACKEND_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS: &[u8] =
106 include_bytes!("../../fixtures/config/no_backend/admin-plaintext-non-admin-systemd-creds.yaml");
107
108const NO_BACKEND_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT: &[u8] =
113 include_bytes!("../../fixtures/config/no_backend/admin-systemd-creds-non-admin-plaintext.yaml");
114
115const NO_BACKEND_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
120 "../../fixtures/config/no_backend/admin-systemd-creds-non-admin-systemd-creds.yaml"
121);
122
123const NO_BACKEND_ADMIN_SSS_NON_ADMIN_PLAINTEXT: &[u8] =
128 include_bytes!("../../fixtures/config/no_backend/admin-sss-non-admin-plaintext.yaml");
129
130const NO_BACKEND_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS: &[u8] =
135 include_bytes!("../../fixtures/config/no_backend/admin-sss-non-admin-systemd-creds.yaml");
136
137const ONLY_NETHSM_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT: &[u8] =
142 include_bytes!("../../fixtures/config/nethsm_backend/admin-plaintext-non-admin-plaintext.yaml");
143
144const ONLY_NETHSM_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
149 "../../fixtures/config/nethsm_backend/admin-plaintext-non-admin-systemd-creds.yaml"
150);
151
152const ONLY_NETHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
157 "../../fixtures/config/nethsm_backend/admin-systemd-creds-non-admin-plaintext.yaml"
158);
159
160const ONLY_NETHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
165 "../../fixtures/config/nethsm_backend/admin-systemd-creds-non-admin-systemd-creds.yaml"
166);
167
168const ONLY_NETHSM_ADMIN_SSS_NON_ADMIN_PLAINTEXT: &[u8] =
173 include_bytes!("../../fixtures/config/nethsm_backend/admin-sss-non-admin-plaintext.yaml");
174
175const ONLY_NETHSM_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS: &[u8] =
180 include_bytes!("../../fixtures/config/nethsm_backend/admin-sss-non-admin-systemd-creds.yaml");
181
182const ONLY_YUBIHSM2_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
187 "../../fixtures/config/yubihsm2_backend/admin-plaintext-non-admin-plaintext.yaml"
188);
189
190const ONLY_YUBIHSM2_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
195 "../../fixtures/config/yubihsm2_backend/admin-plaintext-non-admin-systemd-creds.yaml"
196);
197
198const ONLY_YUBIHSM2_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
203 "../../fixtures/config/yubihsm2_backend/admin-systemd-creds-non-admin-plaintext.yaml"
204);
205
206const ONLY_YUBIHSM2_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
211 "../../fixtures/config/yubihsm2_backend/admin-systemd-creds-non-admin-systemd-creds.yaml"
212);
213
214const ONLY_YUBIHSM2_ADMIN_SSS_NON_ADMIN_PLAINTEXT: &[u8] =
219 include_bytes!("../../fixtures/config/yubihsm2_backend/admin-sss-non-admin-plaintext.yaml");
220
221const ONLY_YUBIHSM2_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS: &[u8] =
226 include_bytes!("../../fixtures/config/yubihsm2_backend/admin-sss-non-admin-systemd-creds.yaml");
227
228const ONLY_YUBIHSM2_MOCKHSM_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
233 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-plaintext-non-admin-plaintext.yaml"
234);
235
236const ONLY_YUBIHSM2_MOCKHSM_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
241 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-plaintext-non-admin-systemd-creds.yaml"
242);
243
244const ONLY_YUBIHSM2_MOCKHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
249 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-systemd-creds-non-admin-plaintext.yaml"
250);
251
252const ONLY_YUBIHSM2_MOCKHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
257 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-systemd-creds-non-admin-systemd-creds.yaml"
258);
259
260const ONLY_YUBIHSM2_MOCKHSM_ADMIN_SSS_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
265 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-sss-non-admin-plaintext.yaml"
266);
267
268const ONLY_YUBIHSM2_MOCKHSM_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
273 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-sss-non-admin-systemd-creds.yaml"
274);
275
276const ALL_BACKENDS_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT: &[u8] =
281 include_bytes!("../../fixtures/config/all_backends/admin-plaintext-non-admin-plaintext.yaml");
282
283const ALL_BACKENDS_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
288 "../../fixtures/config/all_backends/admin-plaintext-non-admin-systemd-creds.yaml"
289);
290
291const ALL_BACKENDS_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
296 "../../fixtures/config/all_backends/admin-systemd-creds-non-admin-plaintext.yaml"
297);
298
299const ALL_BACKENDS_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
304 "../../fixtures/config/all_backends/admin-systemd-creds-non-admin-systemd-creds.yaml"
305);
306
307const ALL_BACKENDS_ADMIN_SSS_NON_ADMIN_PLAINTEXT: &[u8] =
312 include_bytes!("../../fixtures/config/all_backends/admin-sss-non-admin-plaintext.yaml");
313
314const ALL_BACKENDS_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS: &[u8] =
319 include_bytes!("../../fixtures/config/all_backends/admin-sss-non-admin-systemd-creds.yaml");
320
321#[derive(Debug, thiserror::Error)]
323pub enum Error {
324 #[error("Timeout of {timeout}ms reached while {context}")]
326 Timeout {
327 timeout: u64,
329
330 context: String,
332 },
333}
334
335#[derive(Clone, Copy, Debug, Default)]
337pub enum ConfigFileLocation {
338 Run,
340
341 Etc,
343
344 #[default]
346 UsrShare,
347}
348
349impl ConfigFileLocation {
350 pub fn to_parent_dir_path(&self) -> PathBuf {
352 match self {
353 ConfigFileLocation::Run => PathBuf::from(Config::RUN_OVERRIDE_CONFIG_DIR),
354 ConfigFileLocation::Etc => PathBuf::from(Config::ETC_OVERRIDE_CONFIG_DIR),
355 ConfigFileLocation::UsrShare => PathBuf::from(Config::DEFAULT_CONFIG_DIR),
356 }
357 }
358}
359
360impl From<ConfigFileLocation> for PathBuf {
361 fn from(value: ConfigFileLocation) -> Self {
362 value
363 .to_parent_dir_path()
364 .join(format!("{}.yaml", Config::CONFIG_NAME))
365 }
366}
367
368#[derive(Clone, Copy, Debug, Default)]
370pub enum ConfigFileVariant {
371 NoBackendAdminPlaintextNonAdminPlaintext,
376
377 NoBackendAdminPlaintextNonAdminSystemdCreds,
382
383 NoBackendAdminSystemdCredsNonAdminPlaintext,
388
389 NoBackendAdminSystemdCredsNonAdminSystemdCreds,
394
395 NoBackendAdminSssNonAdminPlaintext,
400
401 NoBackendAdminSssNonAdminSystemdCreds,
406
407 OnlyNetHsmBackendAdminPlaintextNonAdminPlaintext,
412
413 OnlyNetHsmBackendAdminPlaintextNonAdminSystemdCreds,
418
419 OnlyNetHsmBackendAdminSystemdCredsNonAdminPlaintext,
424
425 OnlyNetHsmBackendAdminSystemdCredsNonAdminSystemdCreds,
430
431 OnlyNetHsmBackendAdminSssNonAdminPlaintext,
436
437 OnlyNetHsmBackendAdminSssNonAdminSystemdCreds,
442
443 OnlyYubiHsm2BackendAdminPlaintextNonAdminPlaintext,
448
449 OnlyYubiHsm2BackendAdminPlaintextNonAdminSystemdCreds,
454
455 OnlyYubiHsm2BackendAdminSystemdCredsNonAdminPlaintext,
460
461 OnlyYubiHsm2BackendAdminSystemdCredsNonAdminSystemdCreds,
466
467 OnlyYubiHsm2BackendAdminSssNonAdminPlaintext,
472
473 OnlyYubiHsm2BackendAdminSssNonAdminSystemdCreds,
478
479 OnlyYubiHsm2MockHsmBackendAdminPlaintextNonAdminPlaintext,
484
485 OnlyYubiHsm2MockHsmBackendAdminPlaintextNonAdminSystemdCreds,
490
491 OnlyYubiHsm2MockHsmBackendAdminSystemdCredsNonAdminPlaintext,
496
497 OnlyYubiHsm2MockHsmBackendAdminSystemdCredsNonAdminSystemdCreds,
502
503 OnlyYubiHsm2MockHsmBackendAdminSssNonAdminPlaintext,
508
509 OnlyYubiHsm2MockHsmBackendAdminSssNonAdminSystemdCreds,
514
515 AllBackendsAdminPlaintextNonAdminPlaintext,
520
521 AllBackendsAdminPlaintextNonAdminSystemdCreds,
526
527 AllBackendsAdminSystemdCredsNonAdminPlaintext,
532
533 AllBackendsAdminSystemdCredsNonAdminSystemdCreds,
538
539 AllBackendsAdminSssNonAdminPlaintext,
544
545 #[default]
550 AllBackendsAdminSssNonAdminSystemdCreds,
551}
552
553impl ConfigFileVariant {
554 pub fn as_config_bytes(&self) -> &[u8] {
556 match self {
557 ConfigFileVariant::NoBackendAdminPlaintextNonAdminPlaintext => {
558 NO_BACKEND_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT
559 }
560 ConfigFileVariant::NoBackendAdminPlaintextNonAdminSystemdCreds => {
561 NO_BACKEND_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS
562 }
563 ConfigFileVariant::NoBackendAdminSystemdCredsNonAdminPlaintext => {
564 NO_BACKEND_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT
565 }
566 ConfigFileVariant::NoBackendAdminSystemdCredsNonAdminSystemdCreds => {
567 NO_BACKEND_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS
568 }
569 ConfigFileVariant::NoBackendAdminSssNonAdminPlaintext => {
570 NO_BACKEND_ADMIN_SSS_NON_ADMIN_PLAINTEXT
571 }
572 ConfigFileVariant::NoBackendAdminSssNonAdminSystemdCreds => {
573 NO_BACKEND_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS
574 }
575 ConfigFileVariant::OnlyNetHsmBackendAdminPlaintextNonAdminPlaintext => {
576 ONLY_NETHSM_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT
577 }
578 ConfigFileVariant::OnlyNetHsmBackendAdminPlaintextNonAdminSystemdCreds => {
579 ONLY_NETHSM_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS
580 }
581 ConfigFileVariant::OnlyNetHsmBackendAdminSystemdCredsNonAdminPlaintext => {
582 ONLY_NETHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT
583 }
584 ConfigFileVariant::OnlyNetHsmBackendAdminSystemdCredsNonAdminSystemdCreds => {
585 ONLY_NETHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS
586 }
587 ConfigFileVariant::OnlyNetHsmBackendAdminSssNonAdminPlaintext => {
588 ONLY_NETHSM_ADMIN_SSS_NON_ADMIN_PLAINTEXT
589 }
590 ConfigFileVariant::OnlyNetHsmBackendAdminSssNonAdminSystemdCreds => {
591 ONLY_NETHSM_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS
592 }
593 ConfigFileVariant::OnlyYubiHsm2BackendAdminPlaintextNonAdminPlaintext => {
594 ONLY_YUBIHSM2_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT
595 }
596 ConfigFileVariant::OnlyYubiHsm2BackendAdminPlaintextNonAdminSystemdCreds => {
597 ONLY_YUBIHSM2_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS
598 }
599 ConfigFileVariant::OnlyYubiHsm2BackendAdminSystemdCredsNonAdminPlaintext => {
600 ONLY_YUBIHSM2_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT
601 }
602 ConfigFileVariant::OnlyYubiHsm2BackendAdminSystemdCredsNonAdminSystemdCreds => {
603 ONLY_YUBIHSM2_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS
604 }
605 ConfigFileVariant::OnlyYubiHsm2BackendAdminSssNonAdminPlaintext => {
606 ONLY_YUBIHSM2_ADMIN_SSS_NON_ADMIN_PLAINTEXT
607 }
608 ConfigFileVariant::OnlyYubiHsm2BackendAdminSssNonAdminSystemdCreds => {
609 ONLY_YUBIHSM2_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS
610 }
611 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminPlaintextNonAdminPlaintext => {
612 ONLY_YUBIHSM2_MOCKHSM_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT
613 }
614 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminPlaintextNonAdminSystemdCreds => {
615 ONLY_YUBIHSM2_MOCKHSM_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS
616 }
617 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminSystemdCredsNonAdminPlaintext => {
618 ONLY_YUBIHSM2_MOCKHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT
619 }
620 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminSystemdCredsNonAdminSystemdCreds => {
621 ONLY_YUBIHSM2_MOCKHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS
622 }
623 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminSssNonAdminPlaintext => {
624 ONLY_YUBIHSM2_MOCKHSM_ADMIN_SSS_NON_ADMIN_PLAINTEXT
625 }
626 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminSssNonAdminSystemdCreds => {
627 ONLY_YUBIHSM2_MOCKHSM_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS
628 }
629 ConfigFileVariant::AllBackendsAdminPlaintextNonAdminPlaintext => {
630 ALL_BACKENDS_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT
631 }
632 ConfigFileVariant::AllBackendsAdminPlaintextNonAdminSystemdCreds => {
633 ALL_BACKENDS_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS
634 }
635 ConfigFileVariant::AllBackendsAdminSystemdCredsNonAdminPlaintext => {
636 ALL_BACKENDS_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT
637 }
638 ConfigFileVariant::AllBackendsAdminSystemdCredsNonAdminSystemdCreds => {
639 ALL_BACKENDS_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS
640 }
641 ConfigFileVariant::AllBackendsAdminSssNonAdminPlaintext => {
642 ALL_BACKENDS_ADMIN_SSS_NON_ADMIN_PLAINTEXT
643 }
644 ConfigFileVariant::AllBackendsAdminSssNonAdminSystemdCreds => {
645 ALL_BACKENDS_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS
646 }
647 }
648 }
649
650 pub fn to_config(&self) -> Result<Config, crate::Error> {
659 Config::from_str(
660 &String::from_utf8(self.as_config_bytes().to_vec()).map_err(|source| {
661 crate::Error::Utf8String {
662 path: PathBuf::from("/dev/null"),
663 context: "creating a Signstar config object from config fixture bytes"
664 .to_string(),
665 source,
666 }
667 })?,
668 )
669 }
670}
671
672#[derive(Clone, Copy, Debug, Default)]
674pub struct SystemUserConfig {
675 #[cfg(any(feature = "nethsm", feature = "yubihsm2"))]
677 pub create_secrets: bool,
678
679 pub create_ssh_authorized_keys: bool,
681}
682
683#[derive(Clone, Copy, Debug, Default)]
685pub struct ConfigFileConfig {
686 pub location: Option<ConfigFileLocation>,
690
691 pub variant: ConfigFileVariant,
693
694 pub system_user_config: Option<SystemUserConfig>,
700}
701
702fn create_config(
715 location: ConfigFileLocation,
716 variant: ConfigFileVariant,
717) -> Result<(), crate::Error> {
718 create_dir_all(location.to_parent_dir_path()).map_err(|source| crate::Error::IoPath {
719 path: location.to_parent_dir_path(),
720 context: "creating the parent directory for the Signstar config",
721 source,
722 })?;
723 let path = PathBuf::from(location);
724
725 let mut file = File::create(&path).map_err(|source| crate::Error::IoPath {
726 path: path.clone(),
727 context: "creating a Signstar configuration file",
728 source,
729 })?;
730 let config_bytes = variant.as_config_bytes();
731 file.write_all(config_bytes)
732 .map_err(|source| crate::Error::IoPath {
733 path,
734 context: "writing data to a Signstar configuration file",
735 source,
736 })?;
737
738 Ok(())
739}
740
741fn create_unix_users_and_homes(config: &Config) -> Result<(), crate::Error> {
747 let users = config
748 .system_user_ids()
749 .iter()
750 .cloned()
751 .map(|id| id.as_ref())
752 .collect::<Vec<_>>();
753 Ok(create_users(&users, Some(&get_home_base_dir_path()), None)?)
754}
755
756#[derive(Clone, Copy, Debug)]
758pub struct SystemPrepareConfig {
759 pub machine_id: bool,
761
762 pub credentials_socket: bool,
764
765 pub signstar_config: ConfigFileConfig,
767}
768
769impl SystemPrepareConfig {
770 pub fn apply(&self) -> Result<Option<BackgroundProcess>, crate::Error> {
786 if self.machine_id {
787 write_machine_id()?;
788 }
789
790 let background_process = if self.credentials_socket {
791 Some(start_credentials_socket()?)
792 } else {
793 None
794 };
795
796 if let Some(config_file_location) = self.signstar_config.location {
797 create_config(config_file_location, self.signstar_config.variant)?;
798
799 if let Some(system_user_config) = self.signstar_config.system_user_config {
800 let config = Config::from_str(&String::from_utf8_lossy(
801 self.signstar_config.variant.as_config_bytes(),
802 ))?;
803 create_unix_users_and_homes(&config)?;
804 system_user_config.apply(&config)?;
805 }
806 }
807
808 Ok(background_process)
809 }
810}
811
812impl Default for SystemPrepareConfig {
813 fn default() -> Self {
814 Self {
815 machine_id: true,
816 credentials_socket: true,
817 signstar_config: ConfigFileConfig::default(),
818 }
819 }
820}
821
822pub fn list_files_in_dir(path: impl AsRef<Path>) -> Result<(), crate::Error> {
824 let path = path.as_ref();
825 let entries = read_dir(path).map_err(|source| crate::Error::IoPath {
826 path: path.to_path_buf(),
827 context: "reading its children",
828 source,
829 })?;
830
831 for entry in entries {
832 let entry = entry.map_err(|source| crate::Error::IoPath {
833 path: path.to_path_buf(),
834 context: "getting an entry below it",
835 source,
836 })?;
837 let meta = entry.metadata().map_err(|source| crate::Error::IoPath {
838 path: path.to_path_buf(),
839 context: "getting metadata",
840 source,
841 })?;
842
843 debug!(
844 "{} {}/{} {entry:?}",
845 meta.permissions().mode(),
846 meta.st_uid(),
847 meta.st_gid()
848 );
849
850 if meta.is_dir() {
851 list_files_in_dir(entry.path())?;
852 }
853 }
854
855 Ok(())
856}
857
858pub fn get_tmp_config(data: &[u8]) -> Result<NamedTempFile, crate::Error> {
860 let tmp_config = NamedTempFile::new().map_err(|source| crate::Error::Io {
861 context: "creating a temporary configuration file".to_string(),
862 source,
863 })?;
864 write(&tmp_config, data).map_err(|source| crate::Error::IoPath {
865 path: tmp_config.path().to_path_buf(),
866 context: "writing full signstar configuration to temporary file",
867 source,
868 })?;
869 Ok(tmp_config)
870}
871
872pub fn write_machine_id() -> Result<(), crate::Error> {
881 debug!("Write dummy /etc/machine-id, required for systemd-creds");
882 let machine_id = PathBuf::from("/etc/machine-id");
883 std::fs::write(&machine_id, "d3b07384d113edec49eaa6238ad5ff00").map_err(|source| {
884 crate::Error::IoPath {
885 path: machine_id.to_path_buf(),
886 context: "writing machine-id",
887 source,
888 }
889 })?;
890
891 let metadata = machine_id
892 .metadata()
893 .map_err(|source| crate::Error::IoPath {
894 path: machine_id,
895 context: "getting metadata of file",
896 source,
897 })?;
898 debug!(
899 "/etc/machine-id\nmode: {}\nuid: {}\ngid: {}",
900 metadata.permissions().mode(),
901 metadata.st_uid(),
902 metadata.st_gid()
903 );
904 Ok(())
905}
906
907#[derive(Debug)]
912pub struct BackgroundProcess {
913 child: Child,
914 command: String,
915}
916
917impl BackgroundProcess {
918 pub fn kill(&mut self) -> Result<(), crate::Error> {
924 self.child.kill().map_err(|source| crate::Error::Io {
925 context: format!("killing process of command \"{}\"", self.command),
926 source,
927 })
928 }
929}
930
931impl Drop for BackgroundProcess {
932 fn drop(&mut self) {
934 if let Err(error) = self.child.kill() {
935 log::debug!(
936 "Unable to kill background process of command {}:\n{error}",
937 self.command
938 )
939 }
940 }
941}
942
943pub fn start_credentials_socket() -> Result<BackgroundProcess, crate::Error> {
956 let systemd_run_path = PathBuf::from("/run/systemd");
957 let socket_path = PathBuf::from("/run/systemd/io.systemd.Credentials");
958 create_dir_all(&systemd_run_path).map_err(|source| crate::Error::IoPath {
959 path: systemd_run_path.clone(),
960 context: "creating the directory",
961 source,
962 })?;
963
964 let mut command = Command::new(get_command("systemd-socket-activate")?);
966 let command = command.args([
967 "--listen",
968 "/run/systemd/io.systemd.Credentials",
969 "--accept",
970 "--fdname=varlink",
971 "systemd-creds",
972 ]);
973 let child = command.spawn().map_err(|source| crate::Error::IoPath {
974 path: PathBuf::from("/run/systemd/io.systemd.Credentials"),
975 context: "creating a socket using systemd-socket-activate",
976 source,
977 })?;
978
979 let timeout = 10000;
981 let step = 100;
982 let mut elapsed = 0;
983 let mut permissions_set = false;
984 while elapsed < timeout {
985 if socket_path.exists() {
986 debug!("Found {socket_path:?}");
987 set_permissions(socket_path.as_path(), Permissions::from_mode(0o666)).map_err(
988 |source| crate::Error::IoPath {
989 path: socket_path.to_path_buf(),
990 context: "applying permissions",
991 source,
992 },
993 )?;
994 permissions_set = true;
995 break;
996 } else {
997 thread::sleep(time::Duration::from_millis(step));
998 elapsed += step;
999 }
1000 }
1001 if !permissions_set {
1002 return Err(Error::Timeout {
1003 timeout,
1004 context: format!("waiting for {socket_path:?}"),
1005 }
1006 .into());
1007 }
1008
1009 Ok(BackgroundProcess {
1010 child,
1011 command: format!("{command:?}"),
1012 })
1013}
1014
1015#[cfg(feature = "nethsm")]
1026pub fn nethsm_admin_credentials(
1027 config_data: &[u8],
1028) -> Result<NetHsmAdminCredentials, crate::Error> {
1029 let config_file = get_tmp_config(config_data)?;
1030 NetHsmAdminCredentials::load_from_file(
1031 config_file.path(),
1032 AdministrativeSecretHandling::Plaintext,
1033 )
1034}
1035
1036#[cfg(feature = "nethsm")]
1041pub fn create_full_credentials(users: &[UserId]) -> Vec<FullCredentials> {
1042 users
1043 .iter()
1044 .map(|user| FullCredentials::new(user.clone(), Passphrase::generate(Some(30))))
1045 .collect()
1046}