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