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;
15use log::debug;
16#[cfg(feature = "nethsm")]
17use nethsm::{FullCredentials, UserId};
18#[cfg(feature = "nethsm")]
19use rand::{Rng, distributions::Alphanumeric, thread_rng};
20use signstar_common::system_user::get_home_base_dir_path;
21#[cfg(feature = "nethsm")]
22use signstar_crypto::AdministrativeSecretHandling;
23#[cfg(feature = "nethsm")]
24use signstar_crypto::passphrase::Passphrase;
25use tempfile::NamedTempFile;
26use which::which;
27
28use crate::config::{Config, ConfigSystemUserIds};
29#[cfg(feature = "nethsm")]
30use crate::{AdminCredentials, NetHsmAdminCredentials};
31#[cfg(any(feature = "nethsm", feature = "yubihsm2"))]
33pub mod impl_any {
34 use super::*;
35 use crate::config::UserBackendConnectionFilter;
36
37 impl SystemUserConfig {
38 pub fn apply(&self, config: &Config) -> Result<(), Error> {
44 if self.create_secrets {
45 let user_backend_connections =
46 config.user_backend_connections(UserBackendConnectionFilter::NonAdmin);
47
48 for user_backend_connection in user_backend_connections {
49 user_backend_connection.create_non_admin_backend_user_secrets()?;
50 }
51 }
52
53 Ok(())
54 }
55 }
56}
57
58#[cfg(not(any(feature = "nethsm", feature = "yubihsm2")))]
60mod impl_none {
61 use super::*;
62
63 impl SystemUserConfig {
64 pub fn apply(&self, _config: &Config) -> Result<(), Error> {
74 Ok(())
75 }
76 }
77}
78
79const NO_BACKEND_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT: &[u8] =
84 include_bytes!("../../fixtures/config/no_backend/admin-plaintext-non-admin-plaintext.yaml");
85
86const NO_BACKEND_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS: &[u8] =
91 include_bytes!("../../fixtures/config/no_backend/admin-plaintext-non-admin-systemd-creds.yaml");
92
93const NO_BACKEND_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT: &[u8] =
98 include_bytes!("../../fixtures/config/no_backend/admin-systemd-creds-non-admin-plaintext.yaml");
99
100const NO_BACKEND_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
105 "../../fixtures/config/no_backend/admin-systemd-creds-non-admin-systemd-creds.yaml"
106);
107
108const NO_BACKEND_ADMIN_SSS_NON_ADMIN_PLAINTEXT: &[u8] =
113 include_bytes!("../../fixtures/config/no_backend/admin-sss-non-admin-plaintext.yaml");
114
115const NO_BACKEND_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS: &[u8] =
120 include_bytes!("../../fixtures/config/no_backend/admin-sss-non-admin-systemd-creds.yaml");
121
122const ONLY_NETHSM_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT: &[u8] =
127 include_bytes!("../../fixtures/config/nethsm_backend/admin-plaintext-non-admin-plaintext.yaml");
128
129const ONLY_NETHSM_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
134 "../../fixtures/config/nethsm_backend/admin-plaintext-non-admin-systemd-creds.yaml"
135);
136
137const ONLY_NETHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
142 "../../fixtures/config/nethsm_backend/admin-systemd-creds-non-admin-plaintext.yaml"
143);
144
145const ONLY_NETHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
150 "../../fixtures/config/nethsm_backend/admin-systemd-creds-non-admin-systemd-creds.yaml"
151);
152
153const ONLY_NETHSM_ADMIN_SSS_NON_ADMIN_PLAINTEXT: &[u8] =
158 include_bytes!("../../fixtures/config/nethsm_backend/admin-sss-non-admin-plaintext.yaml");
159
160const ONLY_NETHSM_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS: &[u8] =
165 include_bytes!("../../fixtures/config/nethsm_backend/admin-sss-non-admin-systemd-creds.yaml");
166
167const ONLY_YUBIHSM2_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
172 "../../fixtures/config/yubihsm2_backend/admin-plaintext-non-admin-plaintext.yaml"
173);
174
175const ONLY_YUBIHSM2_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
180 "../../fixtures/config/yubihsm2_backend/admin-plaintext-non-admin-systemd-creds.yaml"
181);
182
183const ONLY_YUBIHSM2_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
188 "../../fixtures/config/yubihsm2_backend/admin-systemd-creds-non-admin-plaintext.yaml"
189);
190
191const ONLY_YUBIHSM2_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
196 "../../fixtures/config/yubihsm2_backend/admin-systemd-creds-non-admin-systemd-creds.yaml"
197);
198
199const ONLY_YUBIHSM2_ADMIN_SSS_NON_ADMIN_PLAINTEXT: &[u8] =
204 include_bytes!("../../fixtures/config/yubihsm2_backend/admin-sss-non-admin-plaintext.yaml");
205
206const ONLY_YUBIHSM2_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS: &[u8] =
211 include_bytes!("../../fixtures/config/yubihsm2_backend/admin-sss-non-admin-systemd-creds.yaml");
212
213const ONLY_YUBIHSM2_MOCKHSM_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
218 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-plaintext-non-admin-plaintext.yaml"
219);
220
221const ONLY_YUBIHSM2_MOCKHSM_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
226 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-plaintext-non-admin-systemd-creds.yaml"
227);
228
229const ONLY_YUBIHSM2_MOCKHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
234 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-systemd-creds-non-admin-plaintext.yaml"
235);
236
237const ONLY_YUBIHSM2_MOCKHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
242 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-systemd-creds-non-admin-systemd-creds.yaml"
243);
244
245const ONLY_YUBIHSM2_MOCKHSM_ADMIN_SSS_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
250 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-sss-non-admin-plaintext.yaml"
251);
252
253const ONLY_YUBIHSM2_MOCKHSM_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
258 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-sss-non-admin-systemd-creds.yaml"
259);
260
261const ALL_BACKENDS_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT: &[u8] =
266 include_bytes!("../../fixtures/config/all_backends/admin-plaintext-non-admin-plaintext.yaml");
267
268const ALL_BACKENDS_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
273 "../../fixtures/config/all_backends/admin-plaintext-non-admin-systemd-creds.yaml"
274);
275
276const ALL_BACKENDS_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
281 "../../fixtures/config/all_backends/admin-systemd-creds-non-admin-plaintext.yaml"
282);
283
284const ALL_BACKENDS_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
289 "../../fixtures/config/all_backends/admin-systemd-creds-non-admin-systemd-creds.yaml"
290);
291
292const ALL_BACKENDS_ADMIN_SSS_NON_ADMIN_PLAINTEXT: &[u8] =
297 include_bytes!("../../fixtures/config/all_backends/admin-sss-non-admin-plaintext.yaml");
298
299const ALL_BACKENDS_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS: &[u8] =
304 include_bytes!("../../fixtures/config/all_backends/admin-sss-non-admin-systemd-creds.yaml");
305
306#[derive(Debug, thiserror::Error)]
308pub enum Error {
309 #[error("Unable to apply permissions to {path}:\n{source}")]
311 ApplyPermissions {
312 path: PathBuf,
314
315 source: std::io::Error,
317 },
318
319 #[error(transparent)]
321 ChangeUserRun(#[from] change_user_run::Error),
322
323 #[error("Unable to create directory {dir}:\n{source}")]
325 CreateDirectory {
326 dir: PathBuf,
328
329 source: std::io::Error,
331 },
332
333 #[error("Unable to start socket for io.systemd.Credentials:\n{0}")]
335 CredentialsSocket(#[source] std::io::Error),
336
337 #[error("I/O error while {context}:\n{source}")]
339 Io {
340 context: &'static str,
342
343 source: std::io::Error,
345 },
346
347 #[error("I/O error at {path} while {context}:\n{source}")]
349 IoPath {
350 path: PathBuf,
352
353 context: &'static str,
355
356 source: std::io::Error,
358 },
359
360 #[error("Signstar-config error:\n{0}")]
362 SignstarConfig(#[from] crate::Error),
363
364 #[error("Timeout of {timeout}ms reached while {context}")]
366 Timeout {
367 timeout: u64,
369
370 context: String,
372 },
373
374 #[error("A temporary file for {purpose} cannot be created:\n{source}")]
376 Tmpfile {
377 purpose: &'static str,
379
380 source: std::io::Error,
382 },
383}
384
385#[derive(Clone, Copy, Debug, Default)]
387pub enum ConfigFileLocation {
388 Run,
390
391 Etc,
393
394 #[default]
396 UsrShare,
397}
398
399impl ConfigFileLocation {
400 pub fn to_parent_dir_path(&self) -> PathBuf {
402 match self {
403 ConfigFileLocation::Run => PathBuf::from(Config::RUN_OVERRIDE_CONFIG_DIR),
404 ConfigFileLocation::Etc => PathBuf::from(Config::ETC_OVERRIDE_CONFIG_DIR),
405 ConfigFileLocation::UsrShare => PathBuf::from(Config::DEFAULT_CONFIG_DIR),
406 }
407 }
408}
409
410impl From<ConfigFileLocation> for PathBuf {
411 fn from(value: ConfigFileLocation) -> Self {
412 value
413 .to_parent_dir_path()
414 .join(format!("{}.yaml", Config::CONFIG_NAME))
415 }
416}
417
418#[derive(Clone, Copy, Debug, Default)]
420pub enum ConfigFileVariant {
421 NoBackendAdminPlaintextNonAdminPlaintext,
426
427 NoBackendAdminPlaintextNonAdminSystemdCreds,
432
433 NoBackendAdminSystemdCredsNonAdminPlaintext,
438
439 NoBackendAdminSystemdCredsNonAdminSystemdCreds,
444
445 NoBackendAdminSssNonAdminPlaintext,
450
451 NoBackendAdminSssNonAdminSystemdCreds,
456
457 OnlyNetHsmBackendAdminPlaintextNonAdminPlaintext,
462
463 OnlyNetHsmBackendAdminPlaintextNonAdminSystemdCreds,
468
469 OnlyNetHsmBackendAdminSystemdCredsNonAdminPlaintext,
474
475 OnlyNetHsmBackendAdminSystemdCredsNonAdminSystemdCreds,
480
481 OnlyNetHsmBackendAdminSssNonAdminPlaintext,
486
487 OnlyNetHsmBackendAdminSssNonAdminSystemdCreds,
492
493 OnlyYubiHsm2BackendAdminPlaintextNonAdminPlaintext,
498
499 OnlyYubiHsm2BackendAdminPlaintextNonAdminSystemdCreds,
504
505 OnlyYubiHsm2BackendAdminSystemdCredsNonAdminPlaintext,
510
511 OnlyYubiHsm2BackendAdminSystemdCredsNonAdminSystemdCreds,
516
517 OnlyYubiHsm2BackendAdminSssNonAdminPlaintext,
522
523 OnlyYubiHsm2BackendAdminSssNonAdminSystemdCreds,
528
529 OnlyYubiHsm2MockHsmBackendAdminPlaintextNonAdminPlaintext,
534
535 OnlyYubiHsm2MockHsmBackendAdminPlaintextNonAdminSystemdCreds,
540
541 OnlyYubiHsm2MockHsmBackendAdminSystemdCredsNonAdminPlaintext,
546
547 OnlyYubiHsm2MockHsmBackendAdminSystemdCredsNonAdminSystemdCreds,
552
553 OnlyYubiHsm2MockHsmBackendAdminSssNonAdminPlaintext,
558
559 OnlyYubiHsm2MockHsmBackendAdminSssNonAdminSystemdCreds,
564
565 AllBackendsAdminPlaintextNonAdminPlaintext,
570
571 AllBackendsAdminPlaintextNonAdminSystemdCreds,
576
577 AllBackendsAdminSystemdCredsNonAdminPlaintext,
582
583 AllBackendsAdminSystemdCredsNonAdminSystemdCreds,
588
589 AllBackendsAdminSssNonAdminPlaintext,
594
595 #[default]
600 AllBackendsAdminSssNonAdminSystemdCreds,
601}
602
603impl ConfigFileVariant {
604 pub fn as_config_bytes(&self) -> &[u8] {
606 match self {
607 ConfigFileVariant::NoBackendAdminPlaintextNonAdminPlaintext => {
608 NO_BACKEND_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT
609 }
610 ConfigFileVariant::NoBackendAdminPlaintextNonAdminSystemdCreds => {
611 NO_BACKEND_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS
612 }
613 ConfigFileVariant::NoBackendAdminSystemdCredsNonAdminPlaintext => {
614 NO_BACKEND_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT
615 }
616 ConfigFileVariant::NoBackendAdminSystemdCredsNonAdminSystemdCreds => {
617 NO_BACKEND_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS
618 }
619 ConfigFileVariant::NoBackendAdminSssNonAdminPlaintext => {
620 NO_BACKEND_ADMIN_SSS_NON_ADMIN_PLAINTEXT
621 }
622 ConfigFileVariant::NoBackendAdminSssNonAdminSystemdCreds => {
623 NO_BACKEND_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS
624 }
625 ConfigFileVariant::OnlyNetHsmBackendAdminPlaintextNonAdminPlaintext => {
626 ONLY_NETHSM_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT
627 }
628 ConfigFileVariant::OnlyNetHsmBackendAdminPlaintextNonAdminSystemdCreds => {
629 ONLY_NETHSM_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS
630 }
631 ConfigFileVariant::OnlyNetHsmBackendAdminSystemdCredsNonAdminPlaintext => {
632 ONLY_NETHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT
633 }
634 ConfigFileVariant::OnlyNetHsmBackendAdminSystemdCredsNonAdminSystemdCreds => {
635 ONLY_NETHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS
636 }
637 ConfigFileVariant::OnlyNetHsmBackendAdminSssNonAdminPlaintext => {
638 ONLY_NETHSM_ADMIN_SSS_NON_ADMIN_PLAINTEXT
639 }
640 ConfigFileVariant::OnlyNetHsmBackendAdminSssNonAdminSystemdCreds => {
641 ONLY_NETHSM_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS
642 }
643 ConfigFileVariant::OnlyYubiHsm2BackendAdminPlaintextNonAdminPlaintext => {
644 ONLY_YUBIHSM2_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT
645 }
646 ConfigFileVariant::OnlyYubiHsm2BackendAdminPlaintextNonAdminSystemdCreds => {
647 ONLY_YUBIHSM2_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS
648 }
649 ConfigFileVariant::OnlyYubiHsm2BackendAdminSystemdCredsNonAdminPlaintext => {
650 ONLY_YUBIHSM2_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT
651 }
652 ConfigFileVariant::OnlyYubiHsm2BackendAdminSystemdCredsNonAdminSystemdCreds => {
653 ONLY_YUBIHSM2_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS
654 }
655 ConfigFileVariant::OnlyYubiHsm2BackendAdminSssNonAdminPlaintext => {
656 ONLY_YUBIHSM2_ADMIN_SSS_NON_ADMIN_PLAINTEXT
657 }
658 ConfigFileVariant::OnlyYubiHsm2BackendAdminSssNonAdminSystemdCreds => {
659 ONLY_YUBIHSM2_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS
660 }
661 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminPlaintextNonAdminPlaintext => {
662 ONLY_YUBIHSM2_MOCKHSM_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT
663 }
664 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminPlaintextNonAdminSystemdCreds => {
665 ONLY_YUBIHSM2_MOCKHSM_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS
666 }
667 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminSystemdCredsNonAdminPlaintext => {
668 ONLY_YUBIHSM2_MOCKHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT
669 }
670 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminSystemdCredsNonAdminSystemdCreds => {
671 ONLY_YUBIHSM2_MOCKHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS
672 }
673 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminSssNonAdminPlaintext => {
674 ONLY_YUBIHSM2_MOCKHSM_ADMIN_SSS_NON_ADMIN_PLAINTEXT
675 }
676 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminSssNonAdminSystemdCreds => {
677 ONLY_YUBIHSM2_MOCKHSM_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS
678 }
679 ConfigFileVariant::AllBackendsAdminPlaintextNonAdminPlaintext => {
680 ALL_BACKENDS_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT
681 }
682 ConfigFileVariant::AllBackendsAdminPlaintextNonAdminSystemdCreds => {
683 ALL_BACKENDS_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS
684 }
685 ConfigFileVariant::AllBackendsAdminSystemdCredsNonAdminPlaintext => {
686 ALL_BACKENDS_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT
687 }
688 ConfigFileVariant::AllBackendsAdminSystemdCredsNonAdminSystemdCreds => {
689 ALL_BACKENDS_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS
690 }
691 ConfigFileVariant::AllBackendsAdminSssNonAdminPlaintext => {
692 ALL_BACKENDS_ADMIN_SSS_NON_ADMIN_PLAINTEXT
693 }
694 ConfigFileVariant::AllBackendsAdminSssNonAdminSystemdCreds => {
695 ALL_BACKENDS_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS
696 }
697 }
698 }
699
700 pub fn to_config(&self) -> Result<Config, crate::Error> {
709 Config::from_str(
710 &String::from_utf8(self.as_config_bytes().to_vec()).map_err(|source| {
711 crate::Error::Utf8String {
712 path: PathBuf::from("/dev/null"),
713 context: "creating a Signstar config object from config fixture bytes"
714 .to_string(),
715 source,
716 }
717 })?,
718 )
719 }
720}
721
722#[derive(Clone, Copy, Debug, Default)]
724pub struct SystemUserConfig {
725 #[cfg(any(feature = "nethsm", feature = "yubihsm2"))]
727 pub create_secrets: bool,
728}
729
730#[derive(Clone, Copy, Debug, Default)]
732pub struct ConfigFileConfig {
733 pub location: Option<ConfigFileLocation>,
737
738 pub variant: ConfigFileVariant,
740
741 pub system_user_config: Option<SystemUserConfig>,
747}
748
749fn create_config(location: ConfigFileLocation, variant: ConfigFileVariant) -> Result<(), Error> {
762 create_dir_all(location.to_parent_dir_path()).map_err(|source| Error::IoPath {
763 path: location.to_parent_dir_path(),
764 context: "creating the parent directory for the Signstar config",
765 source,
766 })?;
767 let path = PathBuf::from(location);
768
769 let mut file = File::create(&path).map_err(|source| crate::Error::IoPath {
770 path: path.clone(),
771 context: "creating a Signstar configuration file",
772 source,
773 })?;
774 let config_bytes = variant.as_config_bytes();
775 file.write_all(config_bytes)
776 .map_err(|source| crate::Error::IoPath {
777 path,
778 context: "writing data to a Signstar configuration file",
779 source,
780 })?;
781
782 Ok(())
783}
784
785fn create_unix_users_and_homes(config: &Config) -> Result<(), Error> {
791 let users = config
792 .system_user_ids()
793 .iter()
794 .cloned()
795 .map(|id| id.as_ref())
796 .collect::<Vec<_>>();
797 Ok(create_users(&users, Some(&get_home_base_dir_path()), None)?)
798}
799
800#[derive(Clone, Copy, Debug)]
802pub struct SystemPrepareConfig {
803 pub machine_id: bool,
805
806 pub credentials_socket: bool,
808
809 pub signstar_config: ConfigFileConfig,
811}
812
813impl SystemPrepareConfig {
814 pub fn apply(&self) -> Result<Option<BackgroundProcess>, Error> {
830 if self.machine_id {
831 write_machine_id()?;
832 }
833
834 let background_process = if self.credentials_socket {
835 Some(start_credentials_socket()?)
836 } else {
837 None
838 };
839
840 if let Some(config_file_location) = self.signstar_config.location {
841 create_config(config_file_location, self.signstar_config.variant)?;
842
843 if let Some(system_user_config) = self.signstar_config.system_user_config {
844 let config = Config::from_str(&String::from_utf8_lossy(
845 self.signstar_config.variant.as_config_bytes(),
846 ))?;
847 create_unix_users_and_homes(&config)?;
848 system_user_config.apply(&config)?;
849 }
850 }
851
852 Ok(background_process)
853 }
854}
855
856impl Default for SystemPrepareConfig {
857 fn default() -> Self {
858 Self {
859 machine_id: true,
860 credentials_socket: true,
861 signstar_config: ConfigFileConfig::default(),
862 }
863 }
864}
865
866pub fn list_files_in_dir(path: impl AsRef<Path>) -> Result<(), Error> {
868 let path = path.as_ref();
869 let entries = read_dir(path).map_err(|source| Error::IoPath {
870 path: path.to_path_buf(),
871 context: "reading its children",
872 source,
873 })?;
874
875 for entry in entries {
876 let entry = entry.map_err(|source| Error::IoPath {
877 path: path.to_path_buf(),
878 context: "getting an entry below it",
879 source,
880 })?;
881 let meta = entry.metadata().map_err(|source| Error::IoPath {
882 path: path.to_path_buf(),
883 context: "getting metadata",
884 source,
885 })?;
886
887 debug!(
888 "{} {}/{} {entry:?}",
889 meta.permissions().mode(),
890 meta.st_uid(),
891 meta.st_gid()
892 );
893
894 if meta.is_dir() {
895 list_files_in_dir(entry.path())?;
896 }
897 }
898
899 Ok(())
900}
901
902pub fn get_tmp_config(data: &[u8]) -> Result<NamedTempFile, Error> {
904 let tmp_config = NamedTempFile::new().map_err(|source| Error::Tmpfile {
905 purpose: "full signstar configuration",
906 source,
907 })?;
908 write(&tmp_config, data).map_err(|source| Error::Io {
909 context: "writing full signstar configuration to temporary file",
910 source,
911 })?;
912 Ok(tmp_config)
913}
914
915pub fn write_machine_id() -> Result<(), Error> {
924 debug!("Write dummy /etc/machine-id, required for systemd-creds");
925 let machine_id = PathBuf::from("/etc/machine-id");
926 std::fs::write(&machine_id, "d3b07384d113edec49eaa6238ad5ff00").map_err(|source| {
927 Error::IoPath {
928 path: machine_id.to_path_buf(),
929 context: "writing machine-id",
930 source,
931 }
932 })?;
933
934 let metadata = machine_id.metadata().map_err(|source| Error::IoPath {
935 path: machine_id,
936 context: "getting metadata of file",
937 source,
938 })?;
939 debug!(
940 "/etc/machine-id\nmode: {}\nuid: {}\ngid: {}",
941 metadata.permissions().mode(),
942 metadata.st_uid(),
943 metadata.st_gid()
944 );
945 Ok(())
946}
947
948#[derive(Debug)]
953pub struct BackgroundProcess {
954 child: Child,
955 command: String,
956}
957
958impl BackgroundProcess {
959 pub fn kill(&mut self) -> Result<(), Error> {
965 self.child.kill().map_err(|source| Error::Io {
966 context: "killing process",
967 source,
968 })
969 }
970}
971
972impl Drop for BackgroundProcess {
973 fn drop(&mut self) {
975 if let Err(error) = self.child.kill() {
976 log::debug!(
977 "Unable to kill background process of command {}:\n{error}",
978 self.command
979 )
980 }
981 }
982}
983
984pub fn start_credentials_socket() -> Result<BackgroundProcess, Error> {
997 let systemd_run_path = PathBuf::from("/run/systemd");
998 let socket_path = PathBuf::from("/run/systemd/io.systemd.Credentials");
999 create_dir_all(&systemd_run_path).map_err(|source| Error::CreateDirectory {
1000 dir: systemd_run_path,
1001 source,
1002 })?;
1003
1004 let command = "systemd-socket-activate";
1006 let systemd_socket_activate = which(command).map_err(|source| {
1007 Error::SignstarConfig(
1008 crate::utils::Error::ExecutableNotFound {
1009 command: command.to_string(),
1010 source,
1011 }
1012 .into(),
1013 )
1014 })?;
1015 let mut command = Command::new(systemd_socket_activate);
1016 let command = command.args([
1017 "--listen",
1018 "/run/systemd/io.systemd.Credentials",
1019 "--accept",
1020 "--fdname=varlink",
1021 "systemd-creds",
1022 ]);
1023 let child = command.spawn().map_err(Error::CredentialsSocket)?;
1024
1025 let timeout = 10000;
1027 let step = 100;
1028 let mut elapsed = 0;
1029 let mut permissions_set = false;
1030 while elapsed < timeout {
1031 if socket_path.exists() {
1032 debug!("Found {socket_path:?}");
1033 set_permissions(socket_path.as_path(), Permissions::from_mode(0o666)).map_err(
1034 |source| Error::ApplyPermissions {
1035 path: socket_path.to_path_buf(),
1036 source,
1037 },
1038 )?;
1039 permissions_set = true;
1040 break;
1041 } else {
1042 thread::sleep(time::Duration::from_millis(step));
1043 elapsed += step;
1044 }
1045 }
1046 if !permissions_set {
1047 return Err(Error::Timeout {
1048 timeout,
1049 context: format!("waiting for {socket_path:?}"),
1050 });
1051 }
1052
1053 Ok(BackgroundProcess {
1054 child,
1055 command: format!("{command:?}"),
1056 })
1057}
1058
1059#[cfg(feature = "nethsm")]
1070pub fn nethsm_admin_credentials(config_data: &[u8]) -> Result<NetHsmAdminCredentials, Error> {
1071 let config_file = get_tmp_config(config_data)?;
1072 NetHsmAdminCredentials::load_from_file(
1073 config_file.path(),
1074 AdministrativeSecretHandling::Plaintext,
1075 )
1076 .map_err(Error::SignstarConfig)
1077}
1078
1079#[cfg(feature = "nethsm")]
1084pub fn create_full_credentials(users: &[UserId]) -> Vec<FullCredentials> {
1085 fn create_passphrase() -> String {
1087 thread_rng()
1088 .sample_iter(&Alphanumeric)
1089 .take(30)
1090 .map(char::from)
1091 .collect()
1092 }
1093
1094 users
1095 .iter()
1096 .map(|user| FullCredentials::new(user.clone(), Passphrase::new(create_passphrase())))
1097 .collect()
1098}