]> git.proxmox.com Git - proxmox-backup.git/blob - src/config/mod.rs
update to first proxmox crate split
[proxmox-backup.git] / src / config / mod.rs
1 //! Proxmox Backup Server Configuration library
2 //!
3 //! This library contains helper to read, parse and write the
4 //! configuration files.
5
6 use anyhow::{bail, format_err, Error};
7 use std::path::PathBuf;
8 use nix::sys::stat::Mode;
9 use openssl::rsa::{Rsa};
10 use openssl::x509::{X509Builder};
11 use openssl::pkey::PKey;
12
13 use proxmox_lang::try_block;
14
15 use pbs_buildcfg::{self, configdir};
16
17 pub mod acme;
18 pub mod node;
19 pub mod tfa;
20
21 /// Check configuration directory permissions
22 ///
23 /// For security reasons, we want to make sure they are set correctly:
24 /// * owned by 'backup' user/group
25 /// * nobody else can read (mode 0700)
26 pub fn check_configdir_permissions() -> Result<(), Error> {
27 let cfgdir = pbs_buildcfg::CONFIGDIR;
28
29 let backup_user = pbs_config::backup_user()?;
30 let backup_uid = backup_user.uid.as_raw();
31 let backup_gid = backup_user.gid.as_raw();
32
33 try_block!({
34 let stat = nix::sys::stat::stat(cfgdir)?;
35
36 if stat.st_uid != backup_uid {
37 bail!("wrong user ({} != {})", stat.st_uid, backup_uid);
38 }
39 if stat.st_gid != backup_gid {
40 bail!("wrong group ({} != {})", stat.st_gid, backup_gid);
41 }
42
43 let perm = stat.st_mode & 0o777;
44 if perm != 0o700 {
45 bail!("wrong permission ({:o} != {:o})", perm, 0o700);
46 }
47 Ok(())
48 })
49 .map_err(|err| {
50 format_err!(
51 "configuration directory '{}' permission problem - {}",
52 cfgdir,
53 err
54 )
55 })
56 }
57
58 pub fn create_configdir() -> Result<(), Error> {
59 let cfgdir = pbs_buildcfg::CONFIGDIR;
60
61 match nix::unistd::mkdir(cfgdir, Mode::from_bits_truncate(0o700)) {
62 Ok(()) => {}
63 Err(nix::Error::Sys(nix::errno::Errno::EEXIST)) => {
64 check_configdir_permissions()?;
65 return Ok(());
66 }
67 Err(err) => bail!(
68 "unable to create configuration directory '{}' - {}",
69 cfgdir,
70 err
71 ),
72 }
73
74 let backup_user = pbs_config::backup_user()?;
75
76 nix::unistd::chown(cfgdir, Some(backup_user.uid), Some(backup_user.gid))
77 .map_err(|err| {
78 format_err!(
79 "unable to set configuration directory '{}' permissions - {}",
80 cfgdir,
81 err
82 )
83 })
84 }
85
86 /// Update self signed node certificate.
87 pub fn update_self_signed_cert(force: bool) -> Result<(), Error> {
88
89 let key_path = PathBuf::from(configdir!("/proxy.key"));
90 let cert_path = PathBuf::from(configdir!("/proxy.pem"));
91
92 if key_path.exists() && cert_path.exists() && !force { return Ok(()); }
93
94 let rsa = Rsa::generate(4096).unwrap();
95
96 let priv_pem = rsa.private_key_to_pem()?;
97
98 let mut x509 = X509Builder::new()?;
99
100 x509.set_version(2)?;
101
102 let today = openssl::asn1::Asn1Time::days_from_now(0)?;
103 x509.set_not_before(&today)?;
104 let expire = openssl::asn1::Asn1Time::days_from_now(365*1000)?;
105 x509.set_not_after(&expire)?;
106
107 let nodename = proxmox::tools::nodename();
108 let mut fqdn = nodename.to_owned();
109
110 let resolv_conf = crate::api2::node::dns::read_etc_resolv_conf()?;
111 if let Some(search) = resolv_conf["search"].as_str() {
112 fqdn.push('.');
113 fqdn.push_str(search);
114 }
115
116 // we try to generate an unique 'subject' to avoid browser problems
117 //(reused serial numbers, ..)
118 let uuid = proxmox_uuid::Uuid::generate();
119
120 let mut subject_name = openssl::x509::X509NameBuilder::new()?;
121 subject_name.append_entry_by_text("O", "Proxmox Backup Server")?;
122 subject_name.append_entry_by_text("OU", &format!("{:X}", uuid))?;
123 subject_name.append_entry_by_text("CN", &fqdn)?;
124 let subject_name = subject_name.build();
125
126 x509.set_subject_name(&subject_name)?;
127 x509.set_issuer_name(&subject_name)?;
128
129 let bc = openssl::x509::extension::BasicConstraints::new(); // CA = false
130 let bc = bc.build()?;
131 x509.append_extension(bc)?;
132
133 let usage = openssl::x509::extension::ExtendedKeyUsage::new()
134 .server_auth()
135 .build()?;
136 x509.append_extension(usage)?;
137
138 let context = x509.x509v3_context(None, None);
139
140 let mut alt_names = openssl::x509::extension::SubjectAlternativeName::new();
141
142 alt_names.ip("127.0.0.1");
143 alt_names.ip("::1");
144
145 alt_names.dns("localhost");
146
147 if nodename != "localhost" { alt_names.dns(nodename); }
148 if nodename != fqdn { alt_names.dns(&fqdn); }
149
150 let alt_names = alt_names.build(&context)?;
151
152 x509.append_extension(alt_names)?;
153
154 let pub_pem = rsa.public_key_to_pem()?;
155 let pubkey = PKey::public_key_from_pem(&pub_pem)?;
156
157 x509.set_pubkey(&pubkey)?;
158
159 let context = x509.x509v3_context(None, None);
160 let ext = openssl::x509::extension::SubjectKeyIdentifier::new().build(&context)?;
161 x509.append_extension(ext)?;
162
163 let context = x509.x509v3_context(None, None);
164 let ext = openssl::x509::extension::AuthorityKeyIdentifier::new()
165 .keyid(true)
166 .build(&context)?;
167 x509.append_extension(ext)?;
168
169 let privkey = PKey::from_rsa(rsa)?;
170
171 x509.sign(&privkey, openssl::hash::MessageDigest::sha256())?;
172
173 let x509 = x509.build();
174 let cert_pem = x509.to_pem()?;
175
176 set_proxy_certificate(&cert_pem, &priv_pem)?;
177
178 Ok(())
179 }
180
181 pub(crate) fn set_proxy_certificate(cert_pem: &[u8], key_pem: &[u8]) -> Result<(), Error> {
182 let key_path = PathBuf::from(configdir!("/proxy.key"));
183 let cert_path = PathBuf::from(configdir!("/proxy.pem"));
184
185 create_configdir()?;
186 pbs_config::replace_backup_config(&key_path, key_pem)
187 .map_err(|err| format_err!("error writing certificate private key - {}", err))?;
188 pbs_config::replace_backup_config(&cert_path, &cert_pem)
189 .map_err(|err| format_err!("error writing certificate file - {}", err))?;
190
191 Ok(())
192 }