summaryrefslogtreecommitdiff
path: root/src/auth.rs
blob: c97392162518a43bafed7e823ded6cb7146334cd (plain)
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use nix::unistd::Group;
use crate::{persist, secure};


pub struct Config {
  pub identitys: Vec<(String, bool)>,
}


/// Returns a option containing the config ad the specific pile path.
/// This function will print out config syntax errors to the standard
/// output if it failes to parse certain lines.
/// #### Arguments
/// * `path` - The path to the config file
/// #### Returns
/// * `None` - If the config failed to load
/// * `Some(Config)` - If the config was sucessfully parsed.
pub fn load_config(path: &str) -> Option<Config> {
  let file = match std::fs::read_to_string(path) {
      Err(e) => {
          eprintln!("{}: {}", &path, e);
          return None
      },
      Ok(data) => data
  };

  let mut identitys = vec![];
  for (line_num, line) in file.split("\n").enumerate() {
      let args: Vec<&str> = line.split(" ").collect();
      if line.starts_with("#") || line.trim() == "" {
          continue;
      }
      if args.len() < 2 {
          eprintln!("Error in config at line {}: Not enough arguments", line_num);
          continue;
      }
      let identity: String = args[0].to_string();
      let persist: bool = match args[1].parse() {
          Err(e) => {
              eprintln!("Error in config at line {}: {}", line_num, e);
              continue;
          },
          Ok(data) => data
      };
      identitys.push((identity, persist));
  }
  Some(Config{identitys})
}


/// Returns a vector of group names of the groups the current effective uid is in
/// #### Returns
/// A vector of strings of the groups the user is in. If the vector is empty,
/// either the function coudn't retrieve the users groups, or the user is not in
/// any groups.
fn get_groups() -> Vec<String> {
  let groups = match nix::unistd::getgroups() {
      Ok(data) => data,
      Err(_) => return vec![]
  };
  let names = groups.iter()
      .map(|gid| Group::from_gid(*gid))
      .flatten().flatten()
      .map(|group| group.name)
      .collect();
  names
}


/// Returns if the user is authorized given a sepcific config and user name.
/// #### Arguments
/// * `config` - A config struct contaning the authorization settings for crab
/// * `user` - The name of the user to check is authorized
/// #### Returns
/// * `None` - If the user is not authorized
/// * `Some(bool)` - If the user is authorized, returning the boolean if the
/// user is set to persist
pub fn authorize(config: &Config, user: &str) -> Option<bool> {
  let groups = get_groups();
  for (identity, persist) in &config.identitys {
      if identity.starts_with(":") {
          let group = &identity[1..];
          if groups.contains(&group.to_string()) {
              return Some(persist.clone());
          };
      } else if identity == user {
          return Some(persist.clone());
      }
  }
  None
}


/// Authenticates an authorized user for the current session. 
/// If the user is already persisted, it will attempt to 
/// read the persist file, and then skip authentication if 
/// the is still persisted.
/// #### Arguments
/// * `user` - The login name of the linux user
/// * `persist` - If the user's login should persist
/// #### Returns
/// * `true` - If the user authenticated sucessfully, or the user is persisted
/// * `false` - If the user failed to authenticate
pub fn authenticate(user: &str, persist: bool) -> bool {
  if persist && persist::get_persist(user) {
      secure::elevate_privilages(0, 0);
      return true;
  }
  let input = match rpassword::prompt_password(format!("crab ({}) password: ", user)) {
      Ok(data) => data,
      Err(_) => return false
  };
  let mut auth = match pam::Authenticator::with_password("crab") {
      Ok(data) => data,
      Err(_) => return false
  };
  auth.get_handler().set_credentials(user.to_owned(), input);
  if !auth.authenticate().is_ok() || !auth.open_session().is_ok() {
      return false;
  }
  if persist {
      persist::set_persist(user);
  }
  secure::elevate_privilages(0, 0);
  return true;
}