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