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::{backend::BackendType, 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_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS_SINGLE_CONNECTION: &[u8] = include_bytes!(
157 "../../fixtures/config/nethsm_backend/admin-plaintext-non-admin-systemd-creds-single-connection.yaml"
158);
159
160const ONLY_NETHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
165 "../../fixtures/config/nethsm_backend/admin-systemd-creds-non-admin-plaintext.yaml"
166);
167
168const ONLY_NETHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
173 "../../fixtures/config/nethsm_backend/admin-systemd-creds-non-admin-systemd-creds.yaml"
174);
175
176const ONLY_NETHSM_ADMIN_SSS_NON_ADMIN_PLAINTEXT: &[u8] =
181 include_bytes!("../../fixtures/config/nethsm_backend/admin-sss-non-admin-plaintext.yaml");
182
183const ONLY_NETHSM_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS: &[u8] =
188 include_bytes!("../../fixtures/config/nethsm_backend/admin-sss-non-admin-systemd-creds.yaml");
189
190const ONLY_YUBIHSM2_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
195 "../../fixtures/config/yubihsm2_backend/admin-plaintext-non-admin-plaintext.yaml"
196);
197
198const ONLY_YUBIHSM2_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
203 "../../fixtures/config/yubihsm2_backend/admin-plaintext-non-admin-systemd-creds.yaml"
204);
205
206const ONLY_YUBIHSM2_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
211 "../../fixtures/config/yubihsm2_backend/admin-systemd-creds-non-admin-plaintext.yaml"
212);
213
214const ONLY_YUBIHSM2_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
219 "../../fixtures/config/yubihsm2_backend/admin-systemd-creds-non-admin-systemd-creds.yaml"
220);
221
222const ONLY_YUBIHSM2_ADMIN_SSS_NON_ADMIN_PLAINTEXT: &[u8] =
227 include_bytes!("../../fixtures/config/yubihsm2_backend/admin-sss-non-admin-plaintext.yaml");
228
229const ONLY_YUBIHSM2_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS: &[u8] =
234 include_bytes!("../../fixtures/config/yubihsm2_backend/admin-sss-non-admin-systemd-creds.yaml");
235
236const ONLY_YUBIHSM2_MOCKHSM_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
241 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-plaintext-non-admin-plaintext.yaml"
242);
243
244const ONLY_YUBIHSM2_MOCKHSM_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
249 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-plaintext-non-admin-systemd-creds.yaml"
250);
251
252const ONLY_YUBIHSM2_MOCKHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
257 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-systemd-creds-non-admin-plaintext.yaml"
258);
259
260const ONLY_YUBIHSM2_MOCKHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
265 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-systemd-creds-non-admin-systemd-creds.yaml"
266);
267
268const ONLY_YUBIHSM2_MOCKHSM_ADMIN_SSS_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
273 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-sss-non-admin-plaintext.yaml"
274);
275
276const ONLY_YUBIHSM2_MOCKHSM_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
281 "../../fixtures/config/yubihsm2_mockhsm_backend/admin-sss-non-admin-systemd-creds.yaml"
282);
283
284const ALL_BACKENDS_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT: &[u8] =
289 include_bytes!("../../fixtures/config/all_backends/admin-plaintext-non-admin-plaintext.yaml");
290
291const ALL_BACKENDS_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
296 "../../fixtures/config/all_backends/admin-plaintext-non-admin-systemd-creds.yaml"
297);
298
299const ALL_BACKENDS_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT: &[u8] = include_bytes!(
304 "../../fixtures/config/all_backends/admin-systemd-creds-non-admin-plaintext.yaml"
305);
306
307const ALL_BACKENDS_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS: &[u8] = include_bytes!(
312 "../../fixtures/config/all_backends/admin-systemd-creds-non-admin-systemd-creds.yaml"
313);
314
315const ALL_BACKENDS_ADMIN_SSS_NON_ADMIN_PLAINTEXT: &[u8] =
320 include_bytes!("../../fixtures/config/all_backends/admin-sss-non-admin-plaintext.yaml");
321
322const ALL_BACKENDS_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS: &[u8] =
327 include_bytes!("../../fixtures/config/all_backends/admin-sss-non-admin-systemd-creds.yaml");
328
329#[derive(Debug, thiserror::Error)]
331pub enum Error {
332 #[error("Timeout of {timeout}ms reached while {context}")]
334 Timeout {
335 timeout: u64,
337
338 context: String,
340 },
341}
342
343#[derive(Clone, Copy, Debug, Default)]
345pub enum ConfigFileLocation {
346 Run,
348
349 Etc,
351
352 #[default]
354 UsrShare,
355}
356
357impl ConfigFileLocation {
358 pub fn to_parent_dir_path(&self) -> PathBuf {
360 match self {
361 ConfigFileLocation::Run => PathBuf::from(Config::RUN_OVERRIDE_CONFIG_DIR),
362 ConfigFileLocation::Etc => PathBuf::from(Config::ETC_OVERRIDE_CONFIG_DIR),
363 ConfigFileLocation::UsrShare => PathBuf::from(Config::DEFAULT_CONFIG_DIR),
364 }
365 }
366}
367
368impl From<ConfigFileLocation> for PathBuf {
369 fn from(value: ConfigFileLocation) -> Self {
370 value
371 .to_parent_dir_path()
372 .join(format!("{}.yaml", Config::CONFIG_NAME))
373 }
374}
375
376#[derive(Clone, Copy, Debug, Default)]
378pub enum ConfigFileVariant {
379 NoBackendAdminPlaintextNonAdminPlaintext,
384
385 NoBackendAdminPlaintextNonAdminSystemdCreds,
390
391 NoBackendAdminSystemdCredsNonAdminPlaintext,
396
397 NoBackendAdminSystemdCredsNonAdminSystemdCreds,
402
403 NoBackendAdminSssNonAdminPlaintext,
408
409 NoBackendAdminSssNonAdminSystemdCreds,
414
415 OnlyNetHsmBackendAdminPlaintextNonAdminPlaintext,
420
421 OnlyNetHsmBackendAdminPlaintextNonAdminSystemdCreds,
426
427 OnlyNetHsmBackendAdminPlaintextNonAdminSystemdCredsSingleConnection,
432
433 OnlyNetHsmBackendAdminSystemdCredsNonAdminPlaintext,
438
439 OnlyNetHsmBackendAdminSystemdCredsNonAdminSystemdCreds,
444
445 OnlyNetHsmBackendAdminSssNonAdminPlaintext,
450
451 OnlyNetHsmBackendAdminSssNonAdminSystemdCreds,
456
457 OnlyYubiHsm2BackendAdminPlaintextNonAdminPlaintext,
462
463 OnlyYubiHsm2BackendAdminPlaintextNonAdminSystemdCreds,
468
469 OnlyYubiHsm2BackendAdminSystemdCredsNonAdminPlaintext,
474
475 OnlyYubiHsm2BackendAdminSystemdCredsNonAdminSystemdCreds,
480
481 OnlyYubiHsm2BackendAdminSssNonAdminPlaintext,
486
487 OnlyYubiHsm2BackendAdminSssNonAdminSystemdCreds,
492
493 OnlyYubiHsm2MockHsmBackendAdminPlaintextNonAdminPlaintext,
498
499 OnlyYubiHsm2MockHsmBackendAdminPlaintextNonAdminSystemdCreds,
504
505 OnlyYubiHsm2MockHsmBackendAdminSystemdCredsNonAdminPlaintext,
510
511 OnlyYubiHsm2MockHsmBackendAdminSystemdCredsNonAdminSystemdCreds,
516
517 OnlyYubiHsm2MockHsmBackendAdminSssNonAdminPlaintext,
522
523 OnlyYubiHsm2MockHsmBackendAdminSssNonAdminSystemdCreds,
528
529 AllBackendsAdminPlaintextNonAdminPlaintext,
534
535 AllBackendsAdminPlaintextNonAdminSystemdCreds,
540
541 AllBackendsAdminSystemdCredsNonAdminPlaintext,
546
547 AllBackendsAdminSystemdCredsNonAdminSystemdCreds,
552
553 AllBackendsAdminSssNonAdminPlaintext,
558
559 #[default]
564 AllBackendsAdminSssNonAdminSystemdCreds,
565}
566
567impl ConfigFileVariant {
568 pub fn as_config_bytes(&self) -> &[u8] {
570 match self {
571 ConfigFileVariant::NoBackendAdminPlaintextNonAdminPlaintext => {
572 NO_BACKEND_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT
573 }
574 ConfigFileVariant::NoBackendAdminPlaintextNonAdminSystemdCreds => {
575 NO_BACKEND_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS
576 }
577 ConfigFileVariant::NoBackendAdminSystemdCredsNonAdminPlaintext => {
578 NO_BACKEND_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT
579 }
580 ConfigFileVariant::NoBackendAdminSystemdCredsNonAdminSystemdCreds => {
581 NO_BACKEND_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS
582 }
583 ConfigFileVariant::NoBackendAdminSssNonAdminPlaintext => {
584 NO_BACKEND_ADMIN_SSS_NON_ADMIN_PLAINTEXT
585 }
586 ConfigFileVariant::NoBackendAdminSssNonAdminSystemdCreds => {
587 NO_BACKEND_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS
588 }
589 ConfigFileVariant::OnlyNetHsmBackendAdminPlaintextNonAdminPlaintext => {
590 ONLY_NETHSM_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT
591 }
592 ConfigFileVariant::OnlyNetHsmBackendAdminPlaintextNonAdminSystemdCreds => {
593 ONLY_NETHSM_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS
594 }
595 ConfigFileVariant::OnlyNetHsmBackendAdminPlaintextNonAdminSystemdCredsSingleConnection => {
596 ONLY_NETHSM_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS_SINGLE_CONNECTION
597 }
598 ConfigFileVariant::OnlyNetHsmBackendAdminSystemdCredsNonAdminPlaintext => {
599 ONLY_NETHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT
600 }
601 ConfigFileVariant::OnlyNetHsmBackendAdminSystemdCredsNonAdminSystemdCreds => {
602 ONLY_NETHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS
603 }
604 ConfigFileVariant::OnlyNetHsmBackendAdminSssNonAdminPlaintext => {
605 ONLY_NETHSM_ADMIN_SSS_NON_ADMIN_PLAINTEXT
606 }
607 ConfigFileVariant::OnlyNetHsmBackendAdminSssNonAdminSystemdCreds => {
608 ONLY_NETHSM_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS
609 }
610 ConfigFileVariant::OnlyYubiHsm2BackendAdminPlaintextNonAdminPlaintext => {
611 ONLY_YUBIHSM2_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT
612 }
613 ConfigFileVariant::OnlyYubiHsm2BackendAdminPlaintextNonAdminSystemdCreds => {
614 ONLY_YUBIHSM2_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS
615 }
616 ConfigFileVariant::OnlyYubiHsm2BackendAdminSystemdCredsNonAdminPlaintext => {
617 ONLY_YUBIHSM2_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT
618 }
619 ConfigFileVariant::OnlyYubiHsm2BackendAdminSystemdCredsNonAdminSystemdCreds => {
620 ONLY_YUBIHSM2_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS
621 }
622 ConfigFileVariant::OnlyYubiHsm2BackendAdminSssNonAdminPlaintext => {
623 ONLY_YUBIHSM2_ADMIN_SSS_NON_ADMIN_PLAINTEXT
624 }
625 ConfigFileVariant::OnlyYubiHsm2BackendAdminSssNonAdminSystemdCreds => {
626 ONLY_YUBIHSM2_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS
627 }
628 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminPlaintextNonAdminPlaintext => {
629 ONLY_YUBIHSM2_MOCKHSM_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT
630 }
631 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminPlaintextNonAdminSystemdCreds => {
632 ONLY_YUBIHSM2_MOCKHSM_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS
633 }
634 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminSystemdCredsNonAdminPlaintext => {
635 ONLY_YUBIHSM2_MOCKHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT
636 }
637 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminSystemdCredsNonAdminSystemdCreds => {
638 ONLY_YUBIHSM2_MOCKHSM_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS
639 }
640 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminSssNonAdminPlaintext => {
641 ONLY_YUBIHSM2_MOCKHSM_ADMIN_SSS_NON_ADMIN_PLAINTEXT
642 }
643 ConfigFileVariant::OnlyYubiHsm2MockHsmBackendAdminSssNonAdminSystemdCreds => {
644 ONLY_YUBIHSM2_MOCKHSM_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS
645 }
646 ConfigFileVariant::AllBackendsAdminPlaintextNonAdminPlaintext => {
647 ALL_BACKENDS_ADMIN_PLAINTEXT_NON_ADMIN_PLAINTEXT
648 }
649 ConfigFileVariant::AllBackendsAdminPlaintextNonAdminSystemdCreds => {
650 ALL_BACKENDS_ADMIN_PLAINTEXT_NON_ADMIN_SYSTEMD_CREDS
651 }
652 ConfigFileVariant::AllBackendsAdminSystemdCredsNonAdminPlaintext => {
653 ALL_BACKENDS_ADMIN_SYSTEMD_CREDS_NON_ADMIN_PLAINTEXT
654 }
655 ConfigFileVariant::AllBackendsAdminSystemdCredsNonAdminSystemdCreds => {
656 ALL_BACKENDS_ADMIN_SYSTEMD_CREDS_NON_ADMIN_SYSTEMD_CREDS
657 }
658 ConfigFileVariant::AllBackendsAdminSssNonAdminPlaintext => {
659 ALL_BACKENDS_ADMIN_SSS_NON_ADMIN_PLAINTEXT
660 }
661 ConfigFileVariant::AllBackendsAdminSssNonAdminSystemdCreds => {
662 ALL_BACKENDS_ADMIN_SSS_NON_ADMIN_SYSTEMD_CREDS
663 }
664 }
665 }
666
667 pub fn to_config(&self) -> Result<Config, crate::Error> {
676 Config::from_str(
677 &String::from_utf8(self.as_config_bytes().to_vec()).map_err(|source| {
678 crate::Error::Utf8String {
679 path: PathBuf::from("/dev/null"),
680 context: "creating a Signstar config object from config fixture bytes"
681 .to_string(),
682 source,
683 }
684 })?,
685 )
686 }
687
688 pub fn contains_backend(&self, backend_type: BackendType) -> bool {
690 match backend_type {
691 BackendType::NetHsm => matches!(
692 self,
693 Self::OnlyNetHsmBackendAdminPlaintextNonAdminPlaintext
694 | Self::OnlyNetHsmBackendAdminPlaintextNonAdminSystemdCreds
695 | Self::OnlyNetHsmBackendAdminPlaintextNonAdminSystemdCredsSingleConnection
696 | Self::OnlyNetHsmBackendAdminSystemdCredsNonAdminPlaintext
697 | Self::OnlyNetHsmBackendAdminSystemdCredsNonAdminSystemdCreds
698 | Self::OnlyNetHsmBackendAdminSssNonAdminPlaintext
699 | Self::OnlyNetHsmBackendAdminSssNonAdminSystemdCreds
700 | Self::AllBackendsAdminPlaintextNonAdminPlaintext
701 | Self::AllBackendsAdminPlaintextNonAdminSystemdCreds
702 | Self::AllBackendsAdminSystemdCredsNonAdminPlaintext
703 | Self::AllBackendsAdminSystemdCredsNonAdminSystemdCreds
704 | Self::AllBackendsAdminSssNonAdminPlaintext
705 | Self::AllBackendsAdminSssNonAdminSystemdCreds
706 ),
707 BackendType::YubiHsm2 => matches!(
708 self,
709 Self::OnlyYubiHsm2BackendAdminPlaintextNonAdminPlaintext
710 | Self::OnlyYubiHsm2BackendAdminPlaintextNonAdminSystemdCreds
711 | Self::OnlyYubiHsm2BackendAdminSystemdCredsNonAdminPlaintext
712 | Self::OnlyYubiHsm2BackendAdminSystemdCredsNonAdminSystemdCreds
713 | Self::OnlyYubiHsm2BackendAdminSssNonAdminPlaintext
714 | Self::OnlyYubiHsm2BackendAdminSssNonAdminSystemdCreds
715 | Self::OnlyYubiHsm2MockHsmBackendAdminPlaintextNonAdminPlaintext
716 | Self::OnlyYubiHsm2MockHsmBackendAdminPlaintextNonAdminSystemdCreds
717 | Self::OnlyYubiHsm2MockHsmBackendAdminSystemdCredsNonAdminPlaintext
718 | Self::OnlyYubiHsm2MockHsmBackendAdminSystemdCredsNonAdminSystemdCreds
719 | Self::OnlyYubiHsm2MockHsmBackendAdminSssNonAdminPlaintext
720 | Self::OnlyYubiHsm2MockHsmBackendAdminSssNonAdminSystemdCreds
721 | Self::AllBackendsAdminPlaintextNonAdminPlaintext
722 | Self::AllBackendsAdminPlaintextNonAdminSystemdCreds
723 | Self::AllBackendsAdminSystemdCredsNonAdminPlaintext
724 | Self::AllBackendsAdminSystemdCredsNonAdminSystemdCreds
725 | Self::AllBackendsAdminSssNonAdminPlaintext
726 | Self::AllBackendsAdminSssNonAdminSystemdCreds
727 ),
728 }
729 }
730}
731
732#[derive(Clone, Copy, Debug, Default)]
734pub struct SystemUserConfig {
735 #[cfg(any(feature = "nethsm", feature = "yubihsm2"))]
737 pub create_secrets: bool,
738
739 pub create_ssh_authorized_keys: bool,
741}
742
743#[derive(Clone, Copy, Debug, Default)]
745pub struct ConfigFileConfig {
746 pub location: Option<ConfigFileLocation>,
750
751 pub variant: ConfigFileVariant,
753
754 pub system_user_config: Option<SystemUserConfig>,
760}
761
762fn create_config(
775 location: ConfigFileLocation,
776 variant: ConfigFileVariant,
777) -> Result<(), crate::Error> {
778 create_dir_all(location.to_parent_dir_path()).map_err(|source| crate::Error::IoPath {
779 path: location.to_parent_dir_path(),
780 context: "creating the parent directory for the Signstar config",
781 source,
782 })?;
783 let path = PathBuf::from(location);
784
785 let mut file = File::create(&path).map_err(|source| crate::Error::IoPath {
786 path: path.clone(),
787 context: "creating a Signstar configuration file",
788 source,
789 })?;
790 let config_bytes = variant.as_config_bytes();
791 file.write_all(config_bytes)
792 .map_err(|source| crate::Error::IoPath {
793 path,
794 context: "writing data to a Signstar configuration file",
795 source,
796 })?;
797
798 Ok(())
799}
800
801fn create_unix_users_and_homes(config: &Config) -> Result<(), crate::Error> {
807 let users = config
808 .system_user_ids()
809 .iter()
810 .cloned()
811 .map(|id| id.as_ref())
812 .collect::<Vec<_>>();
813 Ok(create_users(&users, Some(&get_home_base_dir_path()), None)?)
814}
815
816#[derive(Clone, Copy, Debug)]
818pub struct SystemPrepareConfig {
819 pub machine_id: bool,
821
822 pub credentials_socket: bool,
824
825 pub signstar_config: ConfigFileConfig,
827}
828
829impl SystemPrepareConfig {
830 pub fn apply(&self) -> Result<Option<BackgroundProcess>, crate::Error> {
846 if self.machine_id {
847 write_machine_id()?;
848 }
849
850 let background_process = if self.credentials_socket {
851 Some(start_credentials_socket()?)
852 } else {
853 None
854 };
855
856 if let Some(config_file_location) = self.signstar_config.location {
857 create_config(config_file_location, self.signstar_config.variant)?;
858
859 if let Some(system_user_config) = self.signstar_config.system_user_config {
860 let config = Config::from_str(&String::from_utf8_lossy(
861 self.signstar_config.variant.as_config_bytes(),
862 ))?;
863 create_unix_users_and_homes(&config)?;
864 system_user_config.apply(&config)?;
865 }
866 }
867
868 Ok(background_process)
869 }
870}
871
872impl Default for SystemPrepareConfig {
873 fn default() -> Self {
874 Self {
875 machine_id: true,
876 credentials_socket: true,
877 signstar_config: ConfigFileConfig::default(),
878 }
879 }
880}
881
882pub fn list_files_in_dir(path: impl AsRef<Path>) -> Result<(), crate::Error> {
884 let path = path.as_ref();
885 let entries = read_dir(path).map_err(|source| crate::Error::IoPath {
886 path: path.to_path_buf(),
887 context: "reading its children",
888 source,
889 })?;
890
891 for entry in entries {
892 let entry = entry.map_err(|source| crate::Error::IoPath {
893 path: path.to_path_buf(),
894 context: "getting an entry below it",
895 source,
896 })?;
897 let meta = entry.metadata().map_err(|source| crate::Error::IoPath {
898 path: path.to_path_buf(),
899 context: "getting metadata",
900 source,
901 })?;
902
903 debug!(
904 "{} {}/{} {entry:?}",
905 meta.permissions().mode(),
906 meta.st_uid(),
907 meta.st_gid()
908 );
909
910 if meta.is_dir() {
911 list_files_in_dir(entry.path())?;
912 }
913 }
914
915 Ok(())
916}
917
918pub fn get_tmp_config(data: &[u8]) -> Result<NamedTempFile, crate::Error> {
920 let tmp_config = NamedTempFile::new().map_err(|source| crate::Error::Io {
921 context: "creating a temporary configuration file".to_string(),
922 source,
923 })?;
924 write(&tmp_config, data).map_err(|source| crate::Error::IoPath {
925 path: tmp_config.path().to_path_buf(),
926 context: "writing full signstar configuration to temporary file",
927 source,
928 })?;
929 Ok(tmp_config)
930}
931
932pub fn write_machine_id() -> Result<(), crate::Error> {
941 debug!("Write dummy /etc/machine-id, required for systemd-creds");
942 let machine_id = PathBuf::from("/etc/machine-id");
943 std::fs::write(&machine_id, "d3b07384d113edec49eaa6238ad5ff00").map_err(|source| {
944 crate::Error::IoPath {
945 path: machine_id.to_path_buf(),
946 context: "writing machine-id",
947 source,
948 }
949 })?;
950
951 let metadata = machine_id
952 .metadata()
953 .map_err(|source| crate::Error::IoPath {
954 path: machine_id,
955 context: "getting metadata of file",
956 source,
957 })?;
958 debug!(
959 "/etc/machine-id\nmode: {}\nuid: {}\ngid: {}",
960 metadata.permissions().mode(),
961 metadata.st_uid(),
962 metadata.st_gid()
963 );
964 Ok(())
965}
966
967#[derive(Debug)]
972pub struct BackgroundProcess {
973 child: Child,
974 command: String,
975}
976
977impl BackgroundProcess {
978 pub fn kill(&mut self) -> Result<(), crate::Error> {
984 self.child.kill().map_err(|source| crate::Error::Io {
985 context: format!("killing process of command \"{}\"", self.command),
986 source,
987 })
988 }
989}
990
991impl Drop for BackgroundProcess {
992 fn drop(&mut self) {
994 if let Err(error) = self.child.kill() {
995 log::debug!(
996 "Unable to kill background process of command {}:\n{error}",
997 self.command
998 )
999 }
1000 }
1001}
1002
1003pub fn start_credentials_socket() -> Result<BackgroundProcess, crate::Error> {
1016 let systemd_run_path = PathBuf::from("/run/systemd");
1017 let socket_path = PathBuf::from("/run/systemd/io.systemd.Credentials");
1018 create_dir_all(&systemd_run_path).map_err(|source| crate::Error::IoPath {
1019 path: systemd_run_path.clone(),
1020 context: "creating the directory",
1021 source,
1022 })?;
1023
1024 let mut command = Command::new(get_command("systemd-socket-activate")?);
1026 let command = command.args([
1027 "--listen",
1028 "/run/systemd/io.systemd.Credentials",
1029 "--accept",
1030 "--fdname=varlink",
1031 "systemd-creds",
1032 ]);
1033 let child = command.spawn().map_err(|source| crate::Error::IoPath {
1034 path: PathBuf::from("/run/systemd/io.systemd.Credentials"),
1035 context: "creating a socket using systemd-socket-activate",
1036 source,
1037 })?;
1038
1039 let timeout = 10000;
1041 let step = 100;
1042 let mut elapsed = 0;
1043 let mut permissions_set = false;
1044 while elapsed < timeout {
1045 if socket_path.exists() {
1046 debug!("Found {socket_path:?}");
1047 set_permissions(socket_path.as_path(), Permissions::from_mode(0o666)).map_err(
1048 |source| crate::Error::IoPath {
1049 path: socket_path.to_path_buf(),
1050 context: "applying permissions",
1051 source,
1052 },
1053 )?;
1054 permissions_set = true;
1055 break;
1056 } else {
1057 thread::sleep(time::Duration::from_millis(step));
1058 elapsed += step;
1059 }
1060 }
1061 if !permissions_set {
1062 return Err(Error::Timeout {
1063 timeout,
1064 context: format!("waiting for {socket_path:?}"),
1065 }
1066 .into());
1067 }
1068
1069 Ok(BackgroundProcess {
1070 child,
1071 command: format!("{command:?}"),
1072 })
1073}
1074
1075#[cfg(feature = "nethsm")]
1086pub fn nethsm_admin_credentials(
1087 config_data: &[u8],
1088) -> Result<NetHsmAdminCredentials, crate::Error> {
1089 let config_file = get_tmp_config(config_data)?;
1090 NetHsmAdminCredentials::load_from_file(
1091 config_file.path(),
1092 AdministrativeSecretHandling::Plaintext,
1093 )
1094}
1095
1096#[cfg(feature = "nethsm")]
1101pub fn create_full_credentials(users: &[UserId]) -> Vec<FullCredentials> {
1102 users
1103 .iter()
1104 .map(|user| FullCredentials::new(user.clone(), Passphrase::generate(Some(30))))
1105 .collect()
1106}