Merge branch 'master' of ssh://proxdev.maurer-it.com/rust/proxmox-backup

This commit is contained in:
Dietmar Maurer
2021-01-21 10:56:52 +01:00
122 changed files with 521 additions and 614 deletions

View File

@ -74,12 +74,14 @@ pub const ROLE_ADMIN: u64 = std::u64::MAX;
pub const ROLE_NO_ACCESS: u64 = 0;
#[rustfmt::skip]
#[allow(clippy::identity_op)]
/// Audit can view configuration and status information, but not modify it.
pub const ROLE_AUDIT: u64 = 0
| PRIV_SYS_AUDIT
| PRIV_DATASTORE_AUDIT;
#[rustfmt::skip]
#[allow(clippy::identity_op)]
/// Datastore.Admin can do anything on the datastore.
pub const ROLE_DATASTORE_ADMIN: u64 = 0
| PRIV_DATASTORE_AUDIT
@ -90,6 +92,7 @@ pub const ROLE_DATASTORE_ADMIN: u64 = 0
| PRIV_DATASTORE_PRUNE;
#[rustfmt::skip]
#[allow(clippy::identity_op)]
/// Datastore.Reader can read/verify datastore content and do restore
pub const ROLE_DATASTORE_READER: u64 = 0
| PRIV_DATASTORE_AUDIT
@ -97,27 +100,32 @@ pub const ROLE_DATASTORE_READER: u64 = 0
| PRIV_DATASTORE_READ;
#[rustfmt::skip]
#[allow(clippy::identity_op)]
/// Datastore.Backup can do backup and restore, but no prune.
pub const ROLE_DATASTORE_BACKUP: u64 = 0
| PRIV_DATASTORE_BACKUP;
#[rustfmt::skip]
#[allow(clippy::identity_op)]
/// Datastore.PowerUser can do backup, restore, and prune.
pub const ROLE_DATASTORE_POWERUSER: u64 = 0
| PRIV_DATASTORE_PRUNE
| PRIV_DATASTORE_BACKUP;
#[rustfmt::skip]
#[allow(clippy::identity_op)]
/// Datastore.Audit can audit the datastore.
pub const ROLE_DATASTORE_AUDIT: u64 = 0
| PRIV_DATASTORE_AUDIT;
#[rustfmt::skip]
#[allow(clippy::identity_op)]
/// Remote.Audit can audit the remote
pub const ROLE_REMOTE_AUDIT: u64 = 0
| PRIV_REMOTE_AUDIT;
#[rustfmt::skip]
#[allow(clippy::identity_op)]
/// Remote.Admin can do anything on the remote.
pub const ROLE_REMOTE_ADMIN: u64 = 0
| PRIV_REMOTE_AUDIT
@ -125,6 +133,7 @@ pub const ROLE_REMOTE_ADMIN: u64 = 0
| PRIV_REMOTE_READ;
#[rustfmt::skip]
#[allow(clippy::identity_op)]
/// Remote.SyncOperator can do read and prune on the remote.
pub const ROLE_REMOTE_SYNC_OPERATOR: u64 = 0
| PRIV_REMOTE_AUDIT
@ -363,6 +372,7 @@ impl AclTreeNode {
fn extract_group_roles(&self, _user: &Userid, leaf: bool) -> HashMap<String, bool> {
let mut map = HashMap::new();
#[allow(clippy::for_kv_map)]
for (_group, roles) in &self.groups {
let is_member = false; // fixme: check if user is member of the group
if !is_member {
@ -402,7 +412,7 @@ impl AclTreeNode {
}
fn insert_group_role(&mut self, group: String, role: String, propagate: bool) {
let map = self.groups.entry(group).or_insert_with(|| HashMap::new());
let map = self.groups.entry(group).or_insert_with(HashMap::new);
if role == ROLE_NAME_NO_ACCESS {
map.clear();
map.insert(role, propagate);
@ -413,7 +423,7 @@ impl AclTreeNode {
}
fn insert_user_role(&mut self, auth_id: Authid, role: String, propagate: bool) {
let map = self.users.entry(auth_id).or_insert_with(|| HashMap::new());
let map = self.users.entry(auth_id).or_insert_with(HashMap::new);
if role == ROLE_NAME_NO_ACCESS {
map.clear();
map.insert(role, propagate);
@ -435,7 +445,7 @@ impl AclTree {
/// Iterates over the tree looking for a node matching `path`.
pub fn find_node(&mut self, path: &str) -> Option<&mut AclTreeNode> {
let path = split_acl_path(path);
return self.get_node(&path);
self.get_node(&path)
}
fn get_node(&mut self, path: &[&str]) -> Option<&mut AclTreeNode> {
@ -455,7 +465,7 @@ impl AclTree {
node = node
.children
.entry(String::from(*comp))
.or_insert_with(|| AclTreeNode::new());
.or_insert_with(AclTreeNode::new);
}
node
}
@ -521,12 +531,12 @@ impl AclTree {
if *propagate {
role_ug_map1
.entry(role)
.or_insert_with(|| BTreeSet::new())
.or_insert_with(BTreeSet::new)
.insert(auth_id);
} else {
role_ug_map0
.entry(role)
.or_insert_with(|| BTreeSet::new())
.or_insert_with(BTreeSet::new)
.insert(auth_id);
}
}
@ -538,12 +548,12 @@ impl AclTree {
if *propagate {
role_ug_map1
.entry(role)
.or_insert_with(|| BTreeSet::new())
.or_insert_with(BTreeSet::new)
.insert(group);
} else {
role_ug_map0
.entry(role)
.or_insert_with(|| BTreeSet::new())
.or_insert_with(BTreeSet::new)
.insert(group);
}
}
@ -563,7 +573,7 @@ impl AclTree {
});
result_map
.entry(item_list)
.or_insert_with(|| BTreeSet::new())
.or_insert_with(BTreeSet::new)
.insert(item.to_string());
}
result_map
@ -651,8 +661,7 @@ impl AclTree {
if !ROLE_NAMES.contains_key(role) {
bail!("unknown role '{}'", role);
}
if user_or_group.starts_with('@') {
let group = &user_or_group[1..];
if let Some(group) = user_or_group.strip_prefix('@') {
node.insert_group_role(group.to_string(), role.to_string(), propagate);
} else {
node.insert_user_role(user_or_group.parse()?, role.to_string(), propagate);

View File

@ -98,7 +98,7 @@ impl CachedUserInfo {
}
}
return true;
true
}
pub fn check_privs(

View File

@ -135,8 +135,8 @@ pub const DATASTORE_CFG_LOCKFILE: &str = "/etc/proxmox-backup/.datastore.lck";
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
let content = proxmox::tools::fs::file_read_optional_string(DATASTORE_CFG_FILENAME)?;
let content = content.unwrap_or(String::from(""));
let content = proxmox::tools::fs::file_read_optional_string(DATASTORE_CFG_FILENAME)?
.unwrap_or_else(|| "".to_string());
let digest = openssl::sha::sha256(content.as_bytes());
let data = CONFIG.parse(DATASTORE_CFG_FILENAME, &content)?;

View File

@ -68,8 +68,8 @@ pub fn lock() -> Result<std::fs::File, Error> {
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
let content = proxmox::tools::fs::file_read_optional_string(DRIVE_CFG_FILENAME)?;
let content = content.unwrap_or(String::from(""));
let content = proxmox::tools::fs::file_read_optional_string(DRIVE_CFG_FILENAME)?
.unwrap_or_else(|| "".to_string());
let digest = openssl::sha::sha256(content.as_bytes());
let data = CONFIG.parse(DRIVE_CFG_FILENAME, &content)?;

View File

@ -43,8 +43,8 @@ fn init() -> SectionConfig {
config
}
pub const MEDIA_POOL_CFG_FILENAME: &'static str = "/etc/proxmox-backup/media-pool.cfg";
pub const MEDIA_POOL_CFG_LOCKFILE: &'static str = "/etc/proxmox-backup/.media-pool.lck";
pub const MEDIA_POOL_CFG_FILENAME: &str = "/etc/proxmox-backup/media-pool.cfg";
pub const MEDIA_POOL_CFG_LOCKFILE: &str = "/etc/proxmox-backup/.media-pool.lck";
pub fn lock() -> Result<std::fs::File, Error> {
open_file_locked(MEDIA_POOL_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)
@ -52,8 +52,8 @@ pub fn lock() -> Result<std::fs::File, Error> {
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
let content = proxmox::tools::fs::file_read_optional_string(MEDIA_POOL_CFG_FILENAME)?;
let content = content.unwrap_or(String::from(""));
let content = proxmox::tools::fs::file_read_optional_string(MEDIA_POOL_CFG_FILENAME)?
.unwrap_or_else(|| "".to_string());
let digest = openssl::sha::sha256(content.as_bytes());
let data = CONFIG.parse(MEDIA_POOL_CFG_FILENAME, &content)?;

View File

@ -386,9 +386,9 @@ impl NetworkConfig {
pub fn check_mtu(&self, parent_name: &str, child_name: &str) -> Result<(), Error> {
let parent = self.interfaces.get(parent_name)
.ok_or(format_err!("check_mtu - missing parent interface '{}'", parent_name))?;
.ok_or_else(|| format_err!("check_mtu - missing parent interface '{}'", parent_name))?;
let child = self.interfaces.get(child_name)
.ok_or(format_err!("check_mtu - missing child interface '{}'", child_name))?;
.ok_or_else(|| format_err!("check_mtu - missing child interface '{}'", child_name))?;
let child_mtu = match child.mtu {
Some(mtu) => mtu,
@ -515,7 +515,7 @@ pub fn config() -> Result<(NetworkConfig, [u8;32]), Error> {
Some(content) => content,
None => {
let content = proxmox::tools::fs::file_get_optional_contents(NETWORK_INTERFACES_FILENAME)?;
content.unwrap_or(Vec::new())
content.unwrap_or_default()
}
};
@ -577,8 +577,8 @@ pub fn complete_port_list(arg: &str, _param: &HashMap<String, String>) -> Vec<St
Err(_) => return vec![],
};
let arg = arg.clone().trim();
let prefix = if let Some(idx) = arg.rfind(",") { &arg[..idx+1] } else { "" };
let arg = arg.trim();
let prefix = if let Some(idx) = arg.rfind(',') { &arg[..idx+1] } else { "" };
ports.iter().map(|port| format!("{}{}", prefix, port)).collect()
}

View File

@ -51,6 +51,7 @@ pub static IPV4_REVERSE_MASK: &[&str] = &[
lazy_static! {
pub static ref IPV4_MASK_HASH_LOCALNET: HashMap<&'static str, u8> = {
let mut map = HashMap::new();
#[allow(clippy::needless_range_loop)]
for i in 8..32 {
map.insert(IPV4_REVERSE_MASK[i], i as u8);
}
@ -61,22 +62,23 @@ lazy_static! {
pub fn parse_cidr(cidr: &str) -> Result<(String, u8, bool), Error> {
let (address, mask, is_v6) = parse_address_or_cidr(cidr)?;
if let Some(mask) = mask {
return Ok((address, mask, is_v6));
Ok((address, mask, is_v6))
} else {
bail!("missing netmask in '{}'", cidr);
}
}
pub fn check_netmask(mask: u8, is_v6: bool) -> Result<(), Error> {
if is_v6 {
if !(mask >= 1 && mask <= 128) {
bail!("IPv6 mask '{}' is out of range (1..128).", mask);
}
let (ver, min, max) = if is_v6 {
("IPv6", 1, 128)
} else {
if !(mask > 0 && mask <= 32) {
bail!("IPv4 mask '{}' is out of range (1..32).", mask);
}
("IPv4", 1, 32)
};
if !(mask >= min && mask <= max) {
bail!("{} mask '{}' is out of range ({}..{}).", ver, mask, min, max);
}
Ok(())
}
@ -97,18 +99,18 @@ pub fn parse_address_or_cidr(cidr: &str) -> Result<(String, Option<u8>, bool), E
if let Some(mask) = caps.get(2) {
let mask = u8::from_str_radix(mask.as_str(), 10)?;
check_netmask(mask, false)?;
return Ok((address.to_string(), Some(mask), false));
Ok((address.to_string(), Some(mask), false))
} else {
return Ok((address.to_string(), None, false));
Ok((address.to_string(), None, false))
}
} else if let Some(caps) = CIDR_V6_REGEX.captures(&cidr) {
let address = &caps[1];
if let Some(mask) = caps.get(2) {
let mask = u8::from_str_radix(mask.as_str(), 10)?;
check_netmask(mask, true)?;
return Ok((address.to_string(), Some(mask), true));
Ok((address.to_string(), Some(mask), true))
} else {
return Ok((address.to_string(), None, true));
Ok((address.to_string(), None, true))
}
} else {
bail!("invalid address/mask '{}'", cidr);

View File

@ -74,9 +74,9 @@ impl <R: BufRead> Lexer<R> {
}
fn split_line(line: &str) -> VecDeque<(Token, String)> {
if line.starts_with("#") {
if let Some(comment) = line.strip_prefix('#') {
let mut res = VecDeque::new();
res.push_back((Token::Comment, line[1..].trim().to_string()));
res.push_back((Token::Comment, comment.trim().to_string()));
return res;
}
let mut list: VecDeque<(Token, String)> = line.split_ascii_whitespace().map(|text| {
@ -114,14 +114,14 @@ impl <R: BufRead> Iterator for Lexer<R> {
Some(ref mut cur_line) => {
if cur_line.is_empty() {
self.cur_line = None;
return Some(Ok((Token::Newline, String::from("\n"))));
Some(Ok((Token::Newline, String::from("\n"))))
} else {
let (token, text) = cur_line.pop_front().unwrap();
return Some(Ok((token, text)));
Some(Ok((token, text)))
}
}
None => {
return None;
None
}
}
}

View File

@ -29,7 +29,7 @@ impl <R: BufRead> NetworkParser<R> {
bail!("input error - {}", err);
}
Some(Ok((token, _))) => {
return Ok(*token);
Ok(*token)
}
None => {
bail!("got unexpected end of stream (inside peek)");
@ -44,7 +44,7 @@ impl <R: BufRead> NetworkParser<R> {
}
Some(Ok((token, text))) => {
if token == Token::Newline { self.line_nr += 1; }
return Ok((token, text));
Ok((token, text))
}
None => {
bail!("got unexpected end of stream (inside peek)");
@ -215,12 +215,12 @@ impl <R: BufRead> NetworkParser<R> {
Token::Comment => {
let comment = self.eat(Token::Comment)?;
if !address_family_v4 && address_family_v6 {
let mut comments = interface.comments6.take().unwrap_or(String::new());
let mut comments = interface.comments6.take().unwrap_or_default();
if !comments.is_empty() { comments.push('\n'); }
comments.push_str(&comment);
interface.comments6 = Some(comments);
} else {
let mut comments = interface.comments.take().unwrap_or(String::new());
let mut comments = interface.comments.take().unwrap_or_default();
if !comments.is_empty() { comments.push('\n'); }
comments.push_str(&comment);
interface.comments = Some(comments);

View File

@ -92,8 +92,8 @@ pub const REMOTE_CFG_LOCKFILE: &str = "/etc/proxmox-backup/.remote.lck";
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
let content = proxmox::tools::fs::file_read_optional_string(REMOTE_CFG_FILENAME)?;
let content = content.unwrap_or(String::from(""));
let content = proxmox::tools::fs::file_read_optional_string(REMOTE_CFG_FILENAME)?
.unwrap_or_else(|| "".to_string());
let digest = openssl::sha::sha256(content.as_bytes());
let data = CONFIG.parse(REMOTE_CFG_FILENAME, &content)?;

View File

@ -79,7 +79,7 @@ impl From<&SyncJobStatus> for SyncJobConfig {
owner: job_status.owner.clone(),
remote: job_status.remote.clone(),
remote_store: job_status.remote_store.clone(),
remove_vanished: job_status.remove_vanished.clone(),
remove_vanished: job_status.remove_vanished,
comment: job_status.comment.clone(),
schedule: job_status.schedule.clone(),
}
@ -183,8 +183,8 @@ pub const SYNC_CFG_LOCKFILE: &str = "/etc/proxmox-backup/.sync.lck";
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
let content = proxmox::tools::fs::file_read_optional_string(SYNC_CFG_FILENAME)?;
let content = content.unwrap_or(String::from(""));
let content = proxmox::tools::fs::file_read_optional_string(SYNC_CFG_FILENAME)?
.unwrap_or_else(|| "".to_string());
let digest = openssl::sha::sha256(content.as_bytes());
let data = CONFIG.parse(SYNC_CFG_FILENAME, &content)?;

View File

@ -53,7 +53,7 @@ pub struct EncryptionKeyInfo {
}
pub fn compute_tape_key_fingerprint(key: &[u8; 32]) -> Result<Fingerprint, Error> {
let crypt_config = CryptConfig::new(key.clone())?;
let crypt_config = CryptConfig::new(*key)?;
Ok(crypt_config.fingerprint())
}
@ -193,7 +193,7 @@ pub fn insert_key(key: [u8;32], key_config: KeyConfig, force: bool) -> Result<()
};
if !force {
if let Some(_) = config_map.get(&fingerprint) {
if config_map.get(&fingerprint).is_some() {
bail!("encryption key '{}' already exists.", fingerprint);
}
}

View File

@ -1380,14 +1380,14 @@ impl std::str::FromStr for TfaResponse {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Error> {
Ok(if s.starts_with("totp:") {
TfaResponse::Totp(s[5..].to_string())
} else if s.starts_with("u2f:") {
TfaResponse::U2f(serde_json::from_str(&s[4..])?)
} else if s.starts_with("webauthn:") {
TfaResponse::Webauthn(serde_json::from_str(&s[9..])?)
} else if s.starts_with("recovery:") {
TfaResponse::Recovery(s[9..].to_string())
Ok(if let Some(totp) = s.strip_prefix("totp:") {
TfaResponse::Totp(totp.to_string())
} else if let Some(u2f) = s.strip_prefix("u2f:") {
TfaResponse::U2f(serde_json::from_str(u2f)?)
} else if let Some(webauthn) = s.strip_prefix("webauthn:") {
TfaResponse::Webauthn(serde_json::from_str(webauthn)?)
} else if let Some(recovery) = s.strip_prefix("recovery:") {
TfaResponse::Recovery(recovery.to_string())
} else {
bail!("invalid tfa response");
})

View File

@ -157,8 +157,8 @@ pub const USER_CFG_LOCKFILE: &str = "/etc/proxmox-backup/.user.lck";
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
let content = proxmox::tools::fs::file_read_optional_string(USER_CFG_FILENAME)?;
let content = content.unwrap_or(String::from(""));
let content = proxmox::tools::fs::file_read_optional_string(USER_CFG_FILENAME)?
.unwrap_or_else(|| "".to_string());
let digest = openssl::sha::sha256(content.as_bytes());
let mut data = CONFIG.parse(USER_CFG_FILENAME, &content)?;