1use std::io::{Read, Write};
6use std::path::PathBuf;
7
8use error::*;
9use error::ErrorKind::*;
10
11use {
12 ControllIdentifier, ControllerInternal, Controllers, DeviceResource, DeviceResources,
13 Resources, Subsystem,
14};
15
16#[derive(Debug, Clone)]
21pub struct DevicesController {
22 base: PathBuf,
23 path: PathBuf,
24}
25
26#[derive(Debug, Copy, Clone, PartialEq, Eq)]
28pub enum DeviceType {
29 All,
31 Char,
33 Block,
35}
36
37impl Default for DeviceType {
38 fn default() -> Self {
39 DeviceType::All
40 }
41}
42
43impl DeviceType {
44 pub fn to_char(&self) -> char {
46 match self {
47 DeviceType::All => 'a',
48 DeviceType::Char => 'c',
49 DeviceType::Block => 'b',
50 }
51 }
52
53 pub fn from_char(c: Option<char>) -> Option<DeviceType> {
55 match c {
56 Some('a') => Some(DeviceType::All),
57 Some('c') => Some(DeviceType::Char),
58 Some('b') => Some(DeviceType::Block),
59 _ => None,
60 }
61 }
62}
63
64#[derive(Debug, Copy, Clone, PartialEq, Eq)]
66pub enum DevicePermissions {
67 Read,
69 Write,
71 MkNod,
74}
75
76impl DevicePermissions {
77 pub fn to_char(&self) -> char {
79 match self {
80 DevicePermissions::Read => 'r',
81 DevicePermissions::Write => 'w',
82 DevicePermissions::MkNod => 'm',
83 }
84 }
85
86 pub fn from_char(c: char) -> Option<DevicePermissions> {
88 match c {
89 'r' => Some(DevicePermissions::Read),
90 'w' => Some(DevicePermissions::Write),
91 'm' => Some(DevicePermissions::MkNod),
92 _ => None,
93 }
94 }
95
96 pub fn is_valid(s: &str) -> bool {
98 if s == "" {
99 return false;
100 }
101 for i in s.chars() {
102 if i != 'r' && i != 'w' && i != 'm' {
103 return false;
104 }
105 }
106 return true;
107 }
108
109 pub fn all() -> Vec<DevicePermissions> {
111 vec![
112 DevicePermissions::Read,
113 DevicePermissions::Write,
114 DevicePermissions::MkNod,
115 ]
116 }
117
118 pub fn from_str(s: &str) -> Result<Vec<DevicePermissions>> {
120 let mut v = Vec::new();
121 if s == "" {
122 return Ok(v);
123 }
124 for e in s.chars() {
125 let perm = DevicePermissions::from_char(e)
126 .ok_or_else(|| Error::new(ParseError))?;
127 v.push(perm);
128 }
129
130 Ok(v)
131 }
132}
133
134impl ControllerInternal for DevicesController {
135 fn control_type(&self) -> Controllers {
136 Controllers::Devices
137 }
138 fn get_path(&self) -> &PathBuf {
139 &self.path
140 }
141 fn get_path_mut(&mut self) -> &mut PathBuf {
142 &mut self.path
143 }
144 fn get_base(&self) -> &PathBuf {
145 &self.base
146 }
147
148 fn apply(&self, res: &Resources) -> Result<()> {
149 let res: &DeviceResources = &res.devices;
151
152 if res.update_values {
153 for i in &res.devices {
154 if i.allow {
155 let _ = self.allow_device(i.devtype, i.major, i.minor, &i.access);
156 } else {
157 let _ = self.deny_device(i.devtype, i.major, i.minor, &i.access);
158 }
159 }
160 }
161
162 Ok(())
163 }
164}
165
166impl ControllIdentifier for DevicesController {
167 fn controller_type() -> Controllers {
168 Controllers::Devices
169 }
170}
171
172impl<'a> From<&'a Subsystem> for &'a DevicesController {
173 fn from(sub: &'a Subsystem) -> &'a DevicesController {
174 unsafe {
175 match sub {
176 Subsystem::Devices(c) => c,
177 _ => {
178 assert_eq!(1, 0);
179 ::std::mem::uninitialized()
180 }
181 }
182 }
183 }
184}
185
186impl DevicesController {
187 pub fn new(oroot: PathBuf) -> Self {
189 let mut root = oroot;
190 root.push(Self::controller_type().to_string());
191 Self {
192 base: root.clone(),
193 path: root,
194 }
195 }
196
197 pub fn allow_device(
202 &self,
203 devtype: DeviceType,
204 major: i64,
205 minor: i64,
206 perm: &Vec<DevicePermissions>,
207 ) -> Result<()> {
208 let perms = perm
209 .iter()
210 .map(DevicePermissions::to_char)
211 .collect::<String>();
212 let minor = if minor == -1 {
213 "*".to_string()
214 } else {
215 format!("{}", minor)
216 };
217 let major = if major == -1 {
218 "*".to_string()
219 } else {
220 format!("{}", major)
221 };
222 let final_str = format!("{} {}:{} {}", devtype.to_char(), major, minor, perms);
223 self.open_path("devices.allow", true).and_then(|mut file| {
224 file.write_all(final_str.as_ref())
225 .map_err(|e| Error::with_cause(WriteFailed, e))
226 })
227 }
228
229 pub fn deny_device(
234 &self,
235 devtype: DeviceType,
236 major: i64,
237 minor: i64,
238 perm: &Vec<DevicePermissions>,
239 ) -> Result<()> {
240 let perms = perm
241 .iter()
242 .map(DevicePermissions::to_char)
243 .collect::<String>();
244 let minor = if minor == -1 {
245 "*".to_string()
246 } else {
247 format!("{}", minor)
248 };
249 let major = if major == -1 {
250 "*".to_string()
251 } else {
252 format!("{}", major)
253 };
254 let final_str = format!("{} {}:{} {}", devtype.to_char(), major, minor, perms);
255 self.open_path("devices.deny", true).and_then(|mut file| {
256 file.write_all(final_str.as_ref())
257 .map_err(|e| Error::with_cause(WriteFailed, e))
258 })
259 }
260
261 pub fn allowed_devices(&self) -> Result<Vec<DeviceResource>> {
263 self.open_path("devices.list", false).and_then(|mut file| {
264 let mut s = String::new();
265 let res = file.read_to_string(&mut s);
266 match res {
267 Ok(_) => {
268 s.lines().fold(Ok(Vec::new()), |acc, line| {
269 let ls = line.to_string().split(|c| c == ' ' || c == ':').map(|x| x.to_string()).collect::<Vec<String>>();
270 if acc.is_err() || ls.len() != 4 {
271 error!("allowed_devices: acc: {:?}, ls: {:?}", acc, ls);
272 Err(Error::new(ParseError))
273 } else {
274 let devtype = DeviceType::from_char(ls[0].chars().nth(0));
275 let mut major = ls[1].parse::<i64>();
276 let mut minor = ls[2].parse::<i64>();
277 if major.is_err() && ls[1] == "*".to_string() {
278 major = Ok(-1);
279 }
280 if minor.is_err() && ls[2] == "*".to_string() {
281 minor = Ok(-1);
282 }
283 if devtype.is_none() || major.is_err() || minor.is_err() || !DevicePermissions::is_valid(&ls[3]) {
284 error!("allowed_devices: acc: {:?}, ls: {:?}, devtype: {:?}, major {:?} minor {:?} ls3 {:?}",
285 acc, ls, devtype, major, minor, &ls[3]);
286 Err(Error::new(ParseError))
287 } else {
288 let access = DevicePermissions::from_str(&ls[3])?;
289 let mut acc = acc.unwrap();
290 acc.push(DeviceResource {
291 allow: true,
292 devtype: devtype.unwrap(),
293 major: major.unwrap(),
294 minor: minor.unwrap(),
295 access: access,
296 });
297 Ok(acc)
298 }
299 }
300 })
301 },
302 Err(e) => Err(Error::with_cause(ReadFailed, e)),
303 }
304 })
305 }
306}