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