use std::ffi::CString; use std::io::{Error, ErrorKind}; use std::str::FromStr; use chrono::Datelike; use log::LevelFilter; use simple_logger::SimpleLogger; use crate::errors::EmgauwaError; use crate::settings::Permissions; use crate::types::{RelayStates, Weekday}; pub fn init_logging(level: &str) -> Result<(), EmgauwaError> { let log_level: LevelFilter = LevelFilter::from_str(level) .map_err(|_| EmgauwaError::Other(format!("Invalid log level: {}", level)))?; log::trace!("Log level set to {:?}", log_level); SimpleLogger::new() .with_level(log_level) .init() .map_err(|err| EmgauwaError::Other(format!("Failed to initialize logger: {}", err)))?; Ok(()) } // https://blog.lxsang.me/post/id/28.0 pub fn drop_privileges(permissions: &Permissions) -> Result<(), Error> { log::info!( "Dropping privileges to {}:{}", permissions.user, permissions.group ); // the group id need to be set first, because, when the user privileges drop, // we are unable to drop the group privileges if !permissions.group.is_empty() { drop_privileges_group(&permissions.group)?; } if !permissions.user.is_empty() { drop_privileges_user(&permissions.user)?; } Ok(()) } fn drop_privileges_group(group: &str) -> Result<(), Error> { // get the gid from username if let Ok(cstr) = CString::new(group.as_bytes()) { let p = unsafe { libc::getgrnam(cstr.as_ptr()) }; if p.is_null() { return Err(Error::new( ErrorKind::Other, format!("Unable to find group: {}", group), )); } if unsafe { libc::setgid((*p).gr_gid) } != 0 { return Err(Error::new( ErrorKind::Other, format!("Unable set gid for group: {}", group), )); } } else { return Err(Error::new( ErrorKind::Other, format!("Cannot create CString from groupname: {}", group), )); } Ok(()) } fn drop_privileges_user(user: &str) -> Result<(), Error> { // get the uid from username if let Ok(cstr) = CString::new(user.as_bytes()) { let p = unsafe { libc::getpwnam(cstr.as_ptr()) }; if p.is_null() { return Err(Error::new( ErrorKind::Other, format!("Unable to find user: {}", user), )); } if unsafe { libc::setuid((*p).pw_uid) } != 0 { return Err(Error::new( ErrorKind::Other, format!("Unable set uid for user: {}", user), )); } } else { return Err(Error::new( ErrorKind::Other, format!("Cannot create CString from username: {}", user), )); } Ok(()) } pub fn get_weekday() -> Weekday { (chrono::offset::Local::now() .date_naive() .weekday() .number_from_monday() - 1) as Weekday } pub fn printable_relay_states(relay_states: &RelayStates) -> String { let mut relay_debug = String::new(); relay_states.iter().for_each(|state| { relay_debug.push_str(match state { Some(true) => "+", Some(false) => "-", None => "?", }); }); relay_debug }