~goorzhel/radm

radm/src/pam.rs -rw-r--r-- 2.4 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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//! PAM support.

use std::{ffi::CString, str::FromStr};

use anyhow::{anyhow, Context, Result};
use log::{trace, warn};
use nix::unistd::Gid;
use pam::{Client, PasswordConv};

use crate::{
    auth::Authenticator,
    tui::{prompt, EchoInput},
    user::User,
};

/// A basic PAM authenticator that takes a username and password.
pub struct PamPassword<'a> {
    username: String,
    client: Client<'a, PasswordConv>,
}

impl<'a> PamPassword<'a> {
    pub fn new(username: String) -> Result<Self> {
        let client = Client::with_password("radm").context("Couldn't init PAM client")?;
        Ok(Self { username, client })
    }
}

impl<'a> Authenticator for PamPassword<'a> {
    fn authenticate(&mut self) -> Result<()> {
        let username = &self.username;
        let password = prompt("Password", EchoInput::Silent)?;
        trace!("Authenticating {} with password through PAM", username);
        self.client
            .conversation_mut()
            .set_credentials(username, password);
        self.client.authenticate()?;
        self.client.open_session()?;
        Ok(())
    }

    fn username(&self) -> &str {
        &self.username
    }
}

/// A basic PAM authenticator that takes a username and the GID it should belong to.
pub struct PamAutologin<'a> {
    username: String,
    gid: Gid,
    client: Client<'a, PasswordConv>,
}

impl<'a> PamAutologin<'a> {
    pub fn new(username: String, gid: Gid) -> Result<Self> {
        let client = Client::with_password("radm").context("Couldn't init PAM client")?;
        Ok(Self {
            username,
            gid,
            client,
        })
    }
}

impl<'a> Authenticator for PamAutologin<'a> {
    fn authenticate(&mut self) -> Result<()> {
        let username = &self.username;
        trace!("Authenticating {} with autologin through PAM", username);

        let user = User::from_str(username)?;
        let username_c = CString::new(user.name)?;
        let groups = nix::unistd::getgrouplist(&username_c, user.gid)?;

        if !groups.contains(&self.gid) {
            let message = format!("{} not in autologin GID {}", username, self.gid);
            warn!("{}", message);
            return Err(anyhow!(message));
        }

        self.client.conversation_mut().set_credentials(username, "");
        self.client.authenticate()?;
        self.client.open_session()?;

        Ok(())
    }

    fn username(&self) -> &str {
        &self.username
    }
}