]> git.proxmox.com Git - proxmox-backup.git/blobdiff - src/auth_helpers.rs
src/server/worker_task.rs: carefully handle file permissions
[proxmox-backup.git] / src / auth_helpers.rs
index f8805816a822b1704d1e9d9f78dffa1db44fe54e..1ae86e043f2014d15f9eb56be250835b5dd66759 100644 (file)
@@ -9,24 +9,79 @@ use openssl::sha;
 
 use std::path::PathBuf;
 
-pub fn assemble_csrf_prevention_token(
+fn compute_csrf_secret_digest(
+    timestamp: i64,
     secret: &[u8],
     username: &str,
 ) -> String {
 
-    let epoch = std::time::SystemTime::now().duration_since(
-        std::time::SystemTime::UNIX_EPOCH).unwrap().as_secs();
-
     let mut hasher = sha::Sha256::new();
-    let data = format!("{:08X}:{}:", epoch, username);
+    let data = format!("{:08X}:{}:", timestamp, username);
     hasher.update(data.as_bytes());
     hasher.update(secret);
 
-    let digest = base64::encode_config(&hasher.finish(), base64::STANDARD_NO_PAD);
+    base64::encode_config(&hasher.finish(), base64::STANDARD_NO_PAD)
+}
+
+pub fn assemble_csrf_prevention_token(
+    secret: &[u8],
+    username: &str,
+) -> String {
+
+    let epoch = std::time::SystemTime::now().duration_since(
+        std::time::SystemTime::UNIX_EPOCH).unwrap().as_secs() as i64;
+
+    let digest = compute_csrf_secret_digest(epoch, secret, username);
 
     format!("{:08X}:{}", epoch, digest)
 }
 
+pub fn verify_csrf_prevention_token(
+    secret: &[u8],
+    username: &str,
+    token: &str,
+    min_age: i64,
+    max_age: i64,
+) -> Result<i64, Error> {
+
+    use std::collections::VecDeque;
+
+    let mut parts: VecDeque<&str> = token.split(':').collect();
+
+    try_block!({
+
+        if parts.len() != 2 {
+            bail!("format error - wrong number of parts.");
+        }
+
+        let timestamp = parts.pop_front().unwrap();
+        let sig = parts.pop_front().unwrap();
+
+        let ttime = i64::from_str_radix(timestamp, 16).
+            map_err(|err| format_err!("timestamp format error - {}", err))?;
+
+        let digest = compute_csrf_secret_digest(ttime, secret, username);
+
+        if digest != sig {
+            bail!("invalid signature.");
+        }
+
+        let now = std::time::SystemTime::now().duration_since(
+            std::time::SystemTime::UNIX_EPOCH)?.as_secs() as i64;
+
+        let age = now - ttime;
+        if age < min_age {
+            bail!("timestamp newer than expected.");
+        }
+
+        if age > max_age {
+            bail!("timestamp too old.");
+        }
+
+        Ok(age)
+    }).map_err(|err| format_err!("invalid csrf token - {}", err))
+}
+
 pub fn generate_csrf_key() -> Result<(), Error> {
 
     let path = PathBuf::from(configdir!("/csrf.key"));
@@ -39,10 +94,12 @@ pub fn generate_csrf_key() -> Result<(), Error> {
 
     use nix::sys::stat::Mode;
 
-    tools::file_set_contents(
-        &path, &pem, Some(Mode::from_bits_truncate(0o0640)))?;
+    let (_, backup_gid) = tools::getpwnam_ugid("backup")?;
+    let uid = Some(nix::unistd::ROOT);
+    let gid = Some(nix::unistd::Gid::from_raw(backup_gid));
 
-    nix::unistd::chown(&path, Some(nix::unistd::ROOT), Some(nix::unistd::Gid::from_raw(33)))?;
+    tools::file_set_contents_full(
+        &path, &pem, Some(Mode::from_bits_truncate(0o0640)), uid, gid)?;
 
     Ok(())
 }