groups/
lib.rs

1//! This library parses `/etc/group` for information about groups on a system
2//!
3//! Groups are represented in `/etc/group` in the form of:
4//!
5//! `group_name:password:GID:user_list`
6
7use std::fs;
8use std::io::{BufReader,BufRead};
9
10/// Structure used to wrap parsed information from groups database
11#[derive(Debug,PartialEq,Clone)]
12pub struct Group {
13    /// Group's name
14    pub name: String,
15    /// Group's GID
16    pub gid: u32,
17    /// List of users for group
18    pub user_list: Option<Vec<String>>,
19}
20
21
22// Parses a line from `/etc/group`
23// Ignores the 'password' in `group_name:password:GID:user_list`
24fn parse_line(line: String) -> Option<Group> {
25    let mut split: Vec<&str> =  line.split(':').collect();
26    if split.is_empty() { return None; };
27    // Remove 'x' (password)
28    split.remove(1);
29    let mut users = Vec::new();
30    if !split[2].is_empty() {
31        let owned_users: Vec<&str> = split[2].split(',').collect();
32        for user in owned_users {
33            users.push(user.to_string());
34        }
35    }
36    let group = Group {
37        name: String::from(split[0]),
38        gid: split[1].parse::<u32>().unwrap(),
39        user_list:
40            if !users.is_empty() { Some(users) }
41            else { None }
42    };
43    return Some(group);
44}
45
46// Reads the `/etc/group` file and calls `parse_line` per each line
47fn read_group() -> Vec<Group> {
48    let mut groups = Vec::new();
49    let file = match fs::File::open("/etc/group") {
50        Ok(s) => { s },
51        Err(e) => { panic!(e.to_string()) }
52    };
53    let file_buffer = BufReader::new(&file);
54    for line in file_buffer.lines() {
55        match line {
56            Ok(l) => {
57                groups.push(parse_line(l).unwrap());
58            },
59            Err(e) => { panic!(e.to_string()) }
60        }
61
62    }
63    return groups;
64}
65
66/// Gets a group by its GID
67///
68/// #Example
69///
70/// ```
71/// use groups;
72///
73/// let group = groups::get_group_by_gid(1).unwrap();
74/// assert_eq!(group.gid, 1);
75pub fn get_group_by_gid(gid: u32) -> Option<Group> {
76    for group in read_group() {
77        if group.gid == gid {
78            return Some(group);
79        }
80    }
81    return None;
82}
83
84/// Gets a group by its name
85///
86/// #Example
87///
88/// ```
89/// use groups;
90///
91/// let group = groups::get_group_by_name("bin").unwrap();
92/// assert_eq!(group.name, "bin".to_string());
93pub fn get_group_by_name(name: &str) -> Option<Group> {
94    for group in read_group() {
95        if group.name == name {
96            return Some(group);
97        }
98    }
99    return None;
100}
101
102/// Returns all groups within `/etc/group`
103pub fn get_groups() -> Vec<Group> {
104    return read_group();
105}
106
107/// Searches all groups for any user given or their GID
108///
109/// #Example
110///
111/// ```
112/// use groups;
113///
114/// let mut user = String::new();
115/// for (key, value) in std::env::vars() {
116///     if key == "USER" { user = value }
117/// }
118/// let list = groups::get_group_list(&user, None);
119pub fn get_group_list(user_name: &str, gid: Option<u32>) -> Option<Vec<Group>> {
120    let mut list = Vec::new();
121    for group in read_group().iter() {
122        if gid.is_some() {
123            if group.gid == gid.unwrap() && group.name != user_name {
124                list.push(group.clone());
125            }
126        }
127        if group.user_list.is_some() {
128            let users = group.user_list.clone().unwrap();
129            for user in users {
130                if user == user_name { list.push(group.clone()) }
131            }
132        }
133    }
134    if list.is_empty() { return None; }
135    else { return Some(list); }
136}
137
138#[test]
139fn test_parse_line() {
140    let group = parse_line("hell:x:666:trump".to_string()).unwrap();
141
142    assert_eq!(group.name, "hell".to_string());
143    assert_eq!(group.gid, 666);
144    assert_eq!(group.user_list, Some(vec!["trump".to_string()]));
145}
146
147#[test]
148fn test_read_group() {
149    let groups = read_group();
150    for group in groups {
151        println!("{:?}", group);
152    }
153}
154
155#[test]
156fn test_get_group_by_name() {
157    match get_group_by_name("bin") {
158        Some(group) => {
159            assert_eq!(group.name, "bin".to_string());
160        },
161        None => { }
162    };
163}
164
165#[test]
166fn test_get_group_by_gid() {
167    match get_group_by_gid(1) {
168        Some(group) => {
169            assert_eq!(group.gid, 1);
170        },
171        None => { }
172    };
173}
174
175#[test]
176fn test_get_group_list() {
177    let mut user = String::new();
178    for (key, value) in std::env::vars() {
179        if key == "USER" { user = value }
180    }
181    match get_group_list(&user, None) {
182        Some(list) => {
183            for item in list { println!("{:?}", item); }
184        },
185        None => { }
186    };
187}