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