~goorzhel/radm

radm/src/auth.rs -rw-r--r-- 1.5 KiB
d11d708e — Antonio Gurgel 0.6.4 a month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//! Authentication methods.

use anyhow::{anyhow, Context, Result};
use log::{error, info};
use nix::unistd::Gid;

use crate::{
    pam::{PamAutologin, PamPassword},
    system::hostname,
    tui::{prompt, EchoInput},
};

/// Authenticates a user.
pub trait Authenticator {
    fn authenticate(&mut self) -> Result<()>;
    fn username(&self) -> &str; // For lack of trait fields.
}

/// Prompts user to log in.
pub fn login(autologin_gid: Option<Gid>) -> Result<Box<dyn Authenticator>> {
    let mut attempts = 0;
    let max_attempts = 3;
    let hostname = hostname().context("Couldn't get hostname")?;
    let username_prompt = format!("{} login", hostname);

    loop {
        let username = prompt(&username_prompt, EchoInput::Echo)?;
        if username.is_empty() {
            continue;
        }

        if autologin_gid.is_some() {
            let mut pam = PamAutologin::new(username.clone(), autologin_gid.unwrap())?;
            if pam.authenticate().is_ok() {
                return Ok(Box::new(pam));
            }
        }

        let mut pam = PamPassword::new(username)?;
        match pam.authenticate() {
            Err(e) => {
                error!("Couldn't authenticate {}: {}", pam.username(), e);
            }
            Ok(_) => {
                info!("Authenticated {}", pam.username());
                return Ok(Box::new(pam));
            }
        }
        attempts += 1;
        if attempts == max_attempts {
            return Err(anyhow!("Too many login attempts"));
        }
    }
}