1 //! Proxmox Backup Server Configuration library
3 //! This library contains helper to read, parse and write the
4 //! configuration files.
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
;
13 use proxmox
::tools
::fs
::{CreateOptions, replace_file}
;
14 use proxmox
::try_block
;
16 use pbs_buildcfg
::{self, configdir}
;
20 pub mod cached_user_info
;
32 pub mod tape_encryption_keys
;
36 /// Check configuration directory permissions
38 /// For security reasons, we want to make sure they are set correctly:
39 /// * owned by 'backup' user/group
40 /// * nobody else can read (mode 0700)
41 pub fn check_configdir_permissions() -> Result
<(), Error
> {
42 let cfgdir
= pbs_buildcfg
::CONFIGDIR
;
44 let backup_user
= crate::backup
::backup_user()?
;
45 let backup_uid
= backup_user
.uid
.as_raw();
46 let backup_gid
= backup_user
.gid
.as_raw();
49 let stat
= nix
::sys
::stat
::stat(cfgdir
)?
;
51 if stat
.st_uid
!= backup_uid
{
52 bail
!("wrong user ({} != {})", stat
.st_uid
, backup_uid
);
54 if stat
.st_gid
!= backup_gid
{
55 bail
!("wrong group ({} != {})", stat
.st_gid
, backup_gid
);
58 let perm
= stat
.st_mode
& 0o777;
60 bail
!("wrong permission ({:o} != {:o})", perm
, 0o700);
66 "configuration directory '{}' permission problem - {}",
73 pub fn create_configdir() -> Result
<(), Error
> {
74 let cfgdir
= pbs_buildcfg
::CONFIGDIR
;
76 match nix
::unistd
::mkdir(cfgdir
, Mode
::from_bits_truncate(0o700)) {
78 Err(nix
::Error
::Sys(nix
::errno
::Errno
::EEXIST
)) => {
79 check_configdir_permissions()?
;
83 "unable to create configuration directory '{}' - {}",
89 let backup_user
= crate::backup
::backup_user()?
;
91 nix
::unistd
::chown(cfgdir
, Some(backup_user
.uid
), Some(backup_user
.gid
))
94 "unable to set configuration directory '{}' permissions - {}",
101 /// Update self signed node certificate.
102 pub fn update_self_signed_cert(force
: bool
) -> Result
<(), Error
> {
104 let key_path
= PathBuf
::from(configdir
!("/proxy.key"));
105 let cert_path
= PathBuf
::from(configdir
!("/proxy.pem"));
107 if key_path
.exists() && cert_path
.exists() && !force { return Ok(()); }
109 let rsa
= Rsa
::generate(4096).unwrap();
111 let priv_pem
= rsa
.private_key_to_pem()?
;
113 let mut x509
= X509Builder
::new()?
;
115 x509
.set_version(2)?
;
117 let today
= openssl
::asn1
::Asn1Time
::days_from_now(0)?
;
118 x509
.set_not_before(&today
)?
;
119 let expire
= openssl
::asn1
::Asn1Time
::days_from_now(365*1000)?
;
120 x509
.set_not_after(&expire
)?
;
122 let nodename
= proxmox
::tools
::nodename();
123 let mut fqdn
= nodename
.to_owned();
125 let resolv_conf
= crate::api2
::node
::dns
::read_etc_resolv_conf()?
;
126 if let Some(search
) = resolv_conf
["search"].as_str() {
128 fqdn
.push_str(search
);
131 // we try to generate an unique 'subject' to avoid browser problems
132 //(reused serial numbers, ..)
133 let uuid
= proxmox
::tools
::uuid
::Uuid
::generate();
135 let mut subject_name
= openssl
::x509
::X509NameBuilder
::new()?
;
136 subject_name
.append_entry_by_text("O", "Proxmox Backup Server")?
;
137 subject_name
.append_entry_by_text("OU", &format
!("{:X}", uuid
))?
;
138 subject_name
.append_entry_by_text("CN", &fqdn
)?
;
139 let subject_name
= subject_name
.build();
141 x509
.set_subject_name(&subject_name
)?
;
142 x509
.set_issuer_name(&subject_name
)?
;
144 let bc
= openssl
::x509
::extension
::BasicConstraints
::new(); // CA = false
145 let bc
= bc
.build()?
;
146 x509
.append_extension(bc
)?
;
148 let usage
= openssl
::x509
::extension
::ExtendedKeyUsage
::new()
151 x509
.append_extension(usage
)?
;
153 let context
= x509
.x509v3_context(None
, None
);
155 let mut alt_names
= openssl
::x509
::extension
::SubjectAlternativeName
::new();
157 alt_names
.ip("127.0.0.1");
160 alt_names
.dns("localhost");
162 if nodename
!= "localhost" { alt_names.dns(nodename); }
163 if nodename
!= fqdn { alt_names.dns(&fqdn); }
165 let alt_names
= alt_names
.build(&context
)?
;
167 x509
.append_extension(alt_names
)?
;
169 let pub_pem
= rsa
.public_key_to_pem()?
;
170 let pubkey
= PKey
::public_key_from_pem(&pub_pem
)?
;
172 x509
.set_pubkey(&pubkey
)?
;
174 let context
= x509
.x509v3_context(None
, None
);
175 let ext
= openssl
::x509
::extension
::SubjectKeyIdentifier
::new().build(&context
)?
;
176 x509
.append_extension(ext
)?
;
178 let context
= x509
.x509v3_context(None
, None
);
179 let ext
= openssl
::x509
::extension
::AuthorityKeyIdentifier
::new()
182 x509
.append_extension(ext
)?
;
184 let privkey
= PKey
::from_rsa(rsa
)?
;
186 x509
.sign(&privkey
, openssl
::hash
::MessageDigest
::sha256())?
;
188 let x509
= x509
.build();
189 let cert_pem
= x509
.to_pem()?
;
191 set_proxy_certificate(&cert_pem
, &priv_pem
)?
;
196 pub(crate) fn set_proxy_certificate(cert_pem
: &[u8], key_pem
: &[u8]) -> Result
<(), Error
> {
197 let backup_user
= crate::backup
::backup_user()?
;
198 let options
= CreateOptions
::new()
199 .perm(Mode
::from_bits_truncate(0o0640))
200 .owner(nix
::unistd
::ROOT
)
201 .group(backup_user
.gid
);
202 let key_path
= PathBuf
::from(configdir
!("/proxy.key"));
203 let cert_path
= PathBuf
::from(configdir
!("/proxy.pem"));
206 replace_file(&key_path
, &key_pem
, options
.clone())
207 .map_err(|err
| format_err
!("error writing certificate private key - {}", err
))?
;
208 replace_file(&cert_path
, &cert_pem
, options
)
209 .map_err(|err
| format_err
!("error writing certificate file - {}", err
))?
;