2024-02-18 18:50:22 +00:00
|
|
|
use std::ffi::CString;
|
|
|
|
use std::io::{Error, ErrorKind};
|
2023-11-29 13:27:46 +00:00
|
|
|
use std::str::FromStr;
|
|
|
|
|
2023-11-30 00:43:56 +00:00
|
|
|
use chrono::Datelike;
|
2023-11-29 00:03:04 +00:00
|
|
|
use log::LevelFilter;
|
|
|
|
use simple_logger::SimpleLogger;
|
|
|
|
|
2023-12-05 00:42:19 +00:00
|
|
|
use crate::errors::EmgauwaError;
|
2024-02-18 18:50:22 +00:00
|
|
|
use crate::settings::Permissions;
|
2024-04-25 15:21:54 +00:00
|
|
|
use crate::types::{RelayStates, Weekday};
|
2023-11-30 00:43:56 +00:00
|
|
|
|
2023-11-29 00:03:04 +00:00
|
|
|
|
2023-12-05 00:42:19 +00:00
|
|
|
pub fn init_logging(level: &str) -> Result<(), EmgauwaError> {
|
|
|
|
let log_level: LevelFilter = LevelFilter::from_str(level)
|
2023-12-05 00:51:06 +00:00
|
|
|
.map_err(|_| EmgauwaError::Other(format!("Invalid log level: {}", level)))?;
|
2023-11-29 00:03:04 +00:00
|
|
|
log::trace!("Log level set to {:?}", log_level);
|
|
|
|
|
|
|
|
SimpleLogger::new()
|
|
|
|
.with_level(log_level)
|
|
|
|
.init()
|
2023-12-05 00:51:06 +00:00
|
|
|
.map_err(|err| EmgauwaError::Other(format!("Failed to initialize logger: {}", err)))?;
|
2023-12-05 00:42:19 +00:00
|
|
|
|
|
|
|
Ok(())
|
2023-11-29 00:03:04 +00:00
|
|
|
}
|
2023-11-30 00:43:56 +00:00
|
|
|
|
2024-02-18 18:50:22 +00:00
|
|
|
// 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() {
|
2024-03-04 15:28:20 +00:00
|
|
|
return Err(Error::new(
|
|
|
|
ErrorKind::Other,
|
|
|
|
format!("Unable to find group: {}", group),
|
|
|
|
));
|
2024-02-18 18:50:22 +00:00
|
|
|
}
|
|
|
|
if unsafe { libc::setgid((*p).gr_gid) } != 0 {
|
2024-03-04 15:28:20 +00:00
|
|
|
return Err(Error::new(
|
|
|
|
ErrorKind::Other,
|
|
|
|
format!("Unable set gid for group: {}", group),
|
|
|
|
));
|
2024-02-18 18:50:22 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(Error::new(
|
|
|
|
ErrorKind::Other,
|
2024-03-04 15:28:20 +00:00
|
|
|
format!("Cannot create CString from groupname: {}", group),
|
2024-02-18 18:50:22 +00:00
|
|
|
));
|
|
|
|
}
|
|
|
|
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() {
|
2024-03-04 15:28:20 +00:00
|
|
|
return Err(Error::new(
|
|
|
|
ErrorKind::Other,
|
|
|
|
format!("Unable to find user: {}", user),
|
|
|
|
));
|
2024-02-18 18:50:22 +00:00
|
|
|
}
|
|
|
|
if unsafe { libc::setuid((*p).pw_uid) } != 0 {
|
2024-03-04 15:28:20 +00:00
|
|
|
return Err(Error::new(
|
|
|
|
ErrorKind::Other,
|
|
|
|
format!("Unable set uid for user: {}", user),
|
|
|
|
));
|
2024-02-18 18:50:22 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(Error::new(
|
|
|
|
ErrorKind::Other,
|
2024-03-04 15:28:20 +00:00
|
|
|
format!("Cannot create CString from username: {}", user),
|
2024-02-18 18:50:22 +00:00
|
|
|
));
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-11-30 00:43:56 +00:00
|
|
|
pub fn get_weekday() -> Weekday {
|
|
|
|
(chrono::offset::Local::now()
|
|
|
|
.date_naive()
|
|
|
|
.weekday()
|
|
|
|
.number_from_monday()
|
|
|
|
- 1) as Weekday
|
|
|
|
}
|
2024-04-25 15:21:54 +00:00
|
|
|
|
|
|
|
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(&format!(
|
|
|
|
"{}",
|
|
|
|
match state {
|
|
|
|
Some(true) => "+",
|
|
|
|
Some(false) => "-",
|
|
|
|
None => "?",
|
|
|
|
}
|
|
|
|
));
|
|
|
|
});
|
|
|
|
relay_debug
|
|
|
|
}
|