]>
git.proxmox.com Git - proxmox-backup.git/blob - src/auth.rs
e011cdcc8dba2d5e241f433758783df6a7ddc726
1 //! Proxmox Backup Server Authentication
3 //! This library contains helper to authenticate users.
5 use std
::process
::{Command, Stdio}
;
7 use std
::ffi
::{CString, CStr}
;
13 pub trait ProxmoxAuthenticator
{
14 fn authenticate_user(&self, username
: &str, password
: &str) -> Result
<(), Error
>;
15 fn store_password(&self, username
: &str, password
: &str) -> Result
<(), Error
>;
20 impl ProxmoxAuthenticator
for PAM
{
22 fn authenticate_user(&self, username
: &str, password
: &str) -> Result
<(), Error
> {
23 let mut auth
= pam
::Authenticator
::with_password("proxmox-backup-auth").unwrap();
24 auth
.get_handler().set_credentials(username
, password
);
30 fn store_password(&self, username
: &str, password
: &str) -> Result
<(), Error
> {
31 let mut child
= Command
::new("passwd")
33 .stdin(Stdio
::piped())
34 .stderr(Stdio
::piped())
36 .or_else(|err
| Err(format_err
!("unable to set password for '{}' - execute passwd failed: {}", username
, err
)))?
;
38 // Note: passwd reads password twice from stdin (for verify)
39 writeln
!(child
.stdin
.as_mut().unwrap(), "{}\n{}", password
, password
)?
;
41 let output
= child
.wait_with_output()
42 .or_else(|err
| Err(format_err
!("unable to set password for '{}' - wait failed: {}", username
, err
)))?
;
44 if !output
.status
.success() {
45 bail
!("unable to set password for '{}' - {}", username
, String
::from_utf8_lossy(&output
.stderr
));
54 pub fn crypt(password
: &[u8], salt
: &str) -> Result
<String
, Error
> {
58 #[link_name = "crypt"]
59 fn __crypt(key
: *const libc
::c_char
, salt
: *const libc
::c_char
) -> * mut libc
::c_char
;
62 let salt
= CString
::new(salt
)?
;
63 let password
= CString
::new(password
)?
;
68 password
.as_c_str().as_ptr(),
69 salt
.as_c_str().as_ptr()
73 Ok(String
::from(res
.to_str()?
))
77 pub fn encrypt_pw(password
: &str) -> Result
<String
, Error
> {
79 let salt
= proxmox
::sys
::linux
::random_data(8)?
;
80 let salt
= format
!("$5${}$", base64
::encode_config(&salt
, base64
::CRYPT
));
82 crypt(password
.as_bytes(), &salt
)
85 pub fn verify_crypt_pw(password
: &str, enc_password
: &str) -> Result
<(), Error
> {
86 let verify
= crypt(password
.as_bytes(), enc_password
)?
;
87 if &verify
!= enc_password
{
88 bail
!("invalid credentials");
93 const SHADOW_CONFIG_FILENAME
: &str = "/etc/proxmox-backup/shadow.json";
95 impl ProxmoxAuthenticator
for PBS
{
97 fn authenticate_user(&self, username
: &str, password
: &str) -> Result
<(), Error
> {
98 let data
= proxmox
::tools
::fs
::file_get_json(SHADOW_CONFIG_FILENAME
, Some(json
!({}
)))?
;
99 match data
[username
].as_str() {
100 None
=> bail
!("no password set"),
101 Some(enc_password
) => verify_crypt_pw(password
, enc_password
)?
,
106 fn store_password(&self, username
: &str, password
: &str) -> Result
<(), Error
> {
107 let enc_password
= encrypt_pw(password
)?
;
108 let mut data
= proxmox
::tools
::fs
::file_get_json(SHADOW_CONFIG_FILENAME
, Some(json
!({}
)))?
;
109 data
[username
] = enc_password
.into();
111 let mode
= nix
::sys
::stat
::Mode
::from_bits_truncate(0o0600);
112 let options
= proxmox
::tools
::fs
::CreateOptions
::new()
114 .owner(nix
::unistd
::ROOT
)
115 .group(nix
::unistd
::Gid
::from_raw(0));
117 let data
= serde_json
::to_vec_pretty(&data
)?
;
118 proxmox
::tools
::fs
::replace_file(SHADOW_CONFIG_FILENAME
, &data
, options
)?
;
124 pub fn parse_userid(userid
: &str) -> Result
<(String
, String
), Error
> {
125 let data
: Vec
<&str> = userid
.rsplitn(2, '@'
).collect();
128 bail
!("userid '{}' has no realm", userid
);
130 Ok((data
[1].to_owned(), data
[0].to_owned()))
133 /// Lookup the autenticator for the specified realm
134 pub fn lookup_authenticator(realm
: &str) -> Result
<Box
<dyn ProxmoxAuthenticator
>, Error
> {
136 "pam" => Ok(Box
::new(PAM())),
137 "pbs" => Ok(Box
::new(PBS())),
138 _
=> bail
!("unknown realm '{}'", realm
),
142 /// Authenticate users
143 pub fn authenticate_user(userid
: &str, password
: &str) -> Result
<(), Error
> {
144 let (username
, realm
) = parse_userid(userid
)?
;
146 lookup_authenticator(&realm
)?
147 .authenticate_user(&username
, password
)