move token_shadow to pbs_config workspace
Also moved out crypt.rs (libcrypt bindings) to pbs_tools workspace.
This commit is contained in:
parent
6f4228809e
commit
1cb08a0a05
@ -7,6 +7,7 @@ pub mod remote;
|
||||
pub mod sync;
|
||||
pub mod tape_encryption_keys;
|
||||
pub mod tape_job;
|
||||
pub mod token_shadow;
|
||||
pub mod verify;
|
||||
|
||||
use anyhow::{format_err, Error};
|
||||
|
@ -6,9 +6,9 @@ use serde_json::{from_value, Value};
|
||||
|
||||
use proxmox::tools::fs::CreateOptions;
|
||||
|
||||
use crate::api2::types::Authid;
|
||||
use crate::auth;
|
||||
use pbs_config::open_backup_lockfile;
|
||||
use pbs_api_types::Authid;
|
||||
//use crate::auth;
|
||||
use crate::{open_backup_lockfile, BackupLockGuard};
|
||||
|
||||
const LOCK_FILE: &str = pbs_buildcfg::configdir!("/token.shadow.lock");
|
||||
const CONF_FILE: &str = pbs_buildcfg::configdir!("/token.shadow");
|
||||
@ -21,6 +21,11 @@ pub struct ApiTokenSecret {
|
||||
pub secret: String,
|
||||
}
|
||||
|
||||
// Get exclusive lock
|
||||
fn lock_config() -> Result<BackupLockGuard, Error> {
|
||||
open_backup_lockfile(LOCK_FILE, None, true)
|
||||
}
|
||||
|
||||
fn read_file() -> Result<HashMap<Authid, String>, Error> {
|
||||
let json = proxmox::tools::fs::file_get_json(CONF_FILE, Some(Value::Null))?;
|
||||
|
||||
@ -33,7 +38,7 @@ fn read_file() -> Result<HashMap<Authid, String>, Error> {
|
||||
}
|
||||
|
||||
fn write_file(data: HashMap<Authid, String>) -> Result<(), Error> {
|
||||
let backup_user = pbs_config::backup_user()?;
|
||||
let backup_user = crate::backup_user()?;
|
||||
let options = CreateOptions::new()
|
||||
.perm(nix::sys::stat::Mode::from_bits_truncate(0o0640))
|
||||
.owner(backup_user.uid)
|
||||
@ -43,6 +48,7 @@ fn write_file(data: HashMap<Authid, String>) -> Result<(), Error> {
|
||||
proxmox::tools::fs::replace_file(CONF_FILE, &json, options)
|
||||
}
|
||||
|
||||
|
||||
/// Verifies that an entry for given tokenid / API token secret exists
|
||||
pub fn verify_secret(tokenid: &Authid, secret: &str) -> Result<(), Error> {
|
||||
if !tokenid.is_token() {
|
||||
@ -52,7 +58,7 @@ pub fn verify_secret(tokenid: &Authid, secret: &str) -> Result<(), Error> {
|
||||
let data = read_file()?;
|
||||
match data.get(tokenid) {
|
||||
Some(hashed_secret) => {
|
||||
auth::verify_crypt_pw(secret, &hashed_secret)
|
||||
pbs_tools::crypt::verify_crypt_pw(secret, &hashed_secret)
|
||||
},
|
||||
None => bail!("invalid API token"),
|
||||
}
|
||||
@ -64,10 +70,10 @@ pub fn set_secret(tokenid: &Authid, secret: &str) -> Result<(), Error> {
|
||||
bail!("not an API token ID");
|
||||
}
|
||||
|
||||
let _guard = open_backup_lockfile(LOCK_FILE, None, true)?;
|
||||
let _guard = lock_config()?;
|
||||
|
||||
let mut data = read_file()?;
|
||||
let hashed_secret = auth::encrypt_pw(secret)?;
|
||||
let hashed_secret = pbs_tools::crypt::encrypt_pw(secret)?;
|
||||
data.insert(tokenid.clone(), hashed_secret);
|
||||
write_file(data)?;
|
||||
|
||||
@ -80,7 +86,7 @@ pub fn delete_secret(tokenid: &Authid) -> Result<(), Error> {
|
||||
bail!("not an API token ID");
|
||||
}
|
||||
|
||||
let _guard = open_backup_lockfile(LOCK_FILE, None, true)?;
|
||||
let _guard = lock_config()?;
|
||||
|
||||
let mut data = read_file()?;
|
||||
data.remove(tokenid);
|
68
pbs-tools/src/crypt.rs
Normal file
68
pbs-tools/src/crypt.rs
Normal file
@ -0,0 +1,68 @@
|
||||
use std::ffi::CStr;
|
||||
|
||||
use anyhow::{bail, Error};
|
||||
|
||||
// from libcrypt1, 'lib/crypt.h.in'
|
||||
const CRYPT_OUTPUT_SIZE: usize = 384;
|
||||
const CRYPT_MAX_PASSPHRASE_SIZE: usize = 512;
|
||||
const CRYPT_DATA_RESERVED_SIZE: usize = 767;
|
||||
const CRYPT_DATA_INTERNAL_SIZE: usize = 30720;
|
||||
|
||||
#[repr(C)]
|
||||
struct crypt_data {
|
||||
output: [libc::c_char; CRYPT_OUTPUT_SIZE],
|
||||
setting: [libc::c_char; CRYPT_OUTPUT_SIZE],
|
||||
input: [libc::c_char; CRYPT_MAX_PASSPHRASE_SIZE],
|
||||
reserved: [libc::c_char; CRYPT_DATA_RESERVED_SIZE],
|
||||
initialized: libc::c_char,
|
||||
internal: [libc::c_char; CRYPT_DATA_INTERNAL_SIZE],
|
||||
}
|
||||
|
||||
pub fn crypt(password: &[u8], salt: &[u8]) -> Result<String, Error> {
|
||||
#[link(name = "crypt")]
|
||||
extern "C" {
|
||||
#[link_name = "crypt_r"]
|
||||
fn __crypt_r(
|
||||
key: *const libc::c_char,
|
||||
salt: *const libc::c_char,
|
||||
data: *mut crypt_data,
|
||||
) -> *mut libc::c_char;
|
||||
}
|
||||
|
||||
let mut data: crypt_data = unsafe { std::mem::zeroed() };
|
||||
for (i, c) in salt.iter().take(data.setting.len() - 1).enumerate() {
|
||||
data.setting[i] = *c as libc::c_char;
|
||||
}
|
||||
for (i, c) in password.iter().take(data.input.len() - 1).enumerate() {
|
||||
data.input[i] = *c as libc::c_char;
|
||||
}
|
||||
|
||||
let res = unsafe {
|
||||
let status = __crypt_r(
|
||||
&data.input as *const _,
|
||||
&data.setting as *const _,
|
||||
&mut data as *mut _,
|
||||
);
|
||||
if status.is_null() {
|
||||
bail!("internal error: crypt_r returned null pointer");
|
||||
}
|
||||
CStr::from_ptr(&data.output as *const _)
|
||||
};
|
||||
Ok(String::from(res.to_str()?))
|
||||
}
|
||||
|
||||
pub fn encrypt_pw(password: &str) -> Result<String, Error> {
|
||||
|
||||
let salt = proxmox::sys::linux::random_data(8)?;
|
||||
let salt = format!("$5${}$", base64::encode_config(&salt, base64::CRYPT));
|
||||
|
||||
crypt(password.as_bytes(), salt.as_bytes())
|
||||
}
|
||||
|
||||
pub fn verify_crypt_pw(password: &str, enc_password: &str) -> Result<(), Error> {
|
||||
let verify = crypt(password.as_bytes(), enc_password.as_bytes())?;
|
||||
if verify != enc_password {
|
||||
bail!("invalid credentials");
|
||||
}
|
||||
Ok(())
|
||||
}
|
@ -6,6 +6,7 @@ pub mod broadcast_future;
|
||||
pub mod cert;
|
||||
pub mod cli;
|
||||
pub mod compression;
|
||||
pub mod crypt;
|
||||
pub mod crypt_config;
|
||||
pub mod format;
|
||||
pub mod fd;
|
||||
|
@ -13,9 +13,9 @@ use pbs_api_types::{
|
||||
PASSWORD_FORMAT, PROXMOX_CONFIG_DIGEST_SCHEMA, SINGLE_LINE_COMMENT_SCHEMA, Authid,
|
||||
Tokenname, UserWithTokens, Userid,
|
||||
};
|
||||
use pbs_config::token_shadow;
|
||||
|
||||
use crate::config::user;
|
||||
use crate::config::token_shadow;
|
||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_PERMISSIONS_MODIFY};
|
||||
use crate::config::cached_user_info::CachedUserInfo;
|
||||
use pbs_config::open_backup_lockfile;
|
||||
|
75
src/auth.rs
75
src/auth.rs
@ -4,7 +4,6 @@
|
||||
|
||||
use std::process::{Command, Stdio};
|
||||
use std::io::Write;
|
||||
use std::ffi::CStr;
|
||||
|
||||
use anyhow::{bail, format_err, Error};
|
||||
use serde_json::json;
|
||||
@ -19,7 +18,7 @@ pub trait ProxmoxAuthenticator {
|
||||
fn remove_password(&self, username: &UsernameRef) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
pub struct PAM();
|
||||
struct PAM();
|
||||
|
||||
impl ProxmoxAuthenticator for PAM {
|
||||
|
||||
@ -70,73 +69,7 @@ impl ProxmoxAuthenticator for PAM {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PBS();
|
||||
|
||||
// from libcrypt1, 'lib/crypt.h.in'
|
||||
const CRYPT_OUTPUT_SIZE: usize = 384;
|
||||
const CRYPT_MAX_PASSPHRASE_SIZE: usize = 512;
|
||||
const CRYPT_DATA_RESERVED_SIZE: usize = 767;
|
||||
const CRYPT_DATA_INTERNAL_SIZE: usize = 30720;
|
||||
|
||||
#[repr(C)]
|
||||
struct crypt_data {
|
||||
output: [libc::c_char; CRYPT_OUTPUT_SIZE],
|
||||
setting: [libc::c_char; CRYPT_OUTPUT_SIZE],
|
||||
input: [libc::c_char; CRYPT_MAX_PASSPHRASE_SIZE],
|
||||
reserved: [libc::c_char; CRYPT_DATA_RESERVED_SIZE],
|
||||
initialized: libc::c_char,
|
||||
internal: [libc::c_char; CRYPT_DATA_INTERNAL_SIZE],
|
||||
}
|
||||
|
||||
pub fn crypt(password: &[u8], salt: &[u8]) -> Result<String, Error> {
|
||||
#[link(name = "crypt")]
|
||||
extern "C" {
|
||||
#[link_name = "crypt_r"]
|
||||
fn __crypt_r(
|
||||
key: *const libc::c_char,
|
||||
salt: *const libc::c_char,
|
||||
data: *mut crypt_data,
|
||||
) -> *mut libc::c_char;
|
||||
}
|
||||
|
||||
let mut data: crypt_data = unsafe { std::mem::zeroed() };
|
||||
for (i, c) in salt.iter().take(data.setting.len() - 1).enumerate() {
|
||||
data.setting[i] = *c as libc::c_char;
|
||||
}
|
||||
for (i, c) in password.iter().take(data.input.len() - 1).enumerate() {
|
||||
data.input[i] = *c as libc::c_char;
|
||||
}
|
||||
|
||||
let res = unsafe {
|
||||
let status = __crypt_r(
|
||||
&data.input as *const _,
|
||||
&data.setting as *const _,
|
||||
&mut data as *mut _,
|
||||
);
|
||||
if status.is_null() {
|
||||
bail!("internal error: crypt_r returned null pointer");
|
||||
}
|
||||
CStr::from_ptr(&data.output as *const _)
|
||||
};
|
||||
Ok(String::from(res.to_str()?))
|
||||
}
|
||||
|
||||
|
||||
pub fn encrypt_pw(password: &str) -> Result<String, Error> {
|
||||
|
||||
let salt = proxmox::sys::linux::random_data(8)?;
|
||||
let salt = format!("$5${}$", base64::encode_config(&salt, base64::CRYPT));
|
||||
|
||||
crypt(password.as_bytes(), salt.as_bytes())
|
||||
}
|
||||
|
||||
pub fn verify_crypt_pw(password: &str, enc_password: &str) -> Result<(), Error> {
|
||||
let verify = crypt(password.as_bytes(), enc_password.as_bytes())?;
|
||||
if verify != enc_password {
|
||||
bail!("invalid credentials");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
struct PBS();
|
||||
|
||||
const SHADOW_CONFIG_FILENAME: &str = configdir!("/shadow.json");
|
||||
|
||||
@ -146,13 +79,13 @@ impl ProxmoxAuthenticator for PBS {
|
||||
let data = proxmox::tools::fs::file_get_json(SHADOW_CONFIG_FILENAME, Some(json!({})))?;
|
||||
match data[username.as_str()].as_str() {
|
||||
None => bail!("no password set"),
|
||||
Some(enc_password) => verify_crypt_pw(password, enc_password)?,
|
||||
Some(enc_password) => pbs_tools::crypt::verify_crypt_pw(password, enc_password)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn store_password(&self, username: &UsernameRef, password: &str) -> Result<(), Error> {
|
||||
let enc_password = encrypt_pw(password)?;
|
||||
let enc_password = pbs_tools::crypt::encrypt_pw(password)?;
|
||||
let mut data = proxmox::tools::fs::file_get_json(SHADOW_CONFIG_FILENAME, Some(json!({})))?;
|
||||
data[username.as_str()] = enc_password.into();
|
||||
|
||||
|
@ -20,7 +20,6 @@ pub mod cached_user_info;
|
||||
pub mod datastore;
|
||||
pub mod node;
|
||||
pub mod tfa;
|
||||
pub mod token_shadow;
|
||||
pub mod user;
|
||||
|
||||
/// Check configuration directory permissions
|
||||
|
@ -4,6 +4,7 @@ use anyhow::{format_err, Error};
|
||||
use std::sync::Arc;
|
||||
|
||||
use pbs_tools::ticket::{self, Ticket};
|
||||
use pbs_config::token_shadow;
|
||||
|
||||
use crate::api2::types::{Authid, Userid};
|
||||
use crate::auth_helpers::*;
|
||||
@ -131,7 +132,7 @@ impl ApiAuth for UserApiAuth {
|
||||
.decode_utf8()
|
||||
.map_err(|_| format_err!("failed to decode API token header"))?;
|
||||
|
||||
crate::config::token_shadow::verify_secret(&tokenid, &tokensecret)?;
|
||||
token_shadow::verify_secret(&tokenid, &tokensecret)?;
|
||||
|
||||
Ok(tokenid)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user