|
|
@ -54,10 +54,6 @@ pub enum SystemStoreInitState {
|
|
|
|
Unchanged,
|
|
|
|
Unchanged,
|
|
|
|
/// The system store was present, root settings were updated
|
|
|
|
/// The system store was present, root settings were updated
|
|
|
|
UpdatedRoot,
|
|
|
|
UpdatedRoot,
|
|
|
|
/// the system store was present, auth was previously enabled but is now disabled
|
|
|
|
|
|
|
|
UpdatedAuthDisabled,
|
|
|
|
|
|
|
|
/// the system store was present, auth was previously disabled but is now enabled
|
|
|
|
|
|
|
|
UpdatedAuthEnabled,
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
@ -77,56 +73,55 @@ impl SystemStoreInit {
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// - If it doesn't exist, create it
|
|
|
|
/// - If it doesn't exist, create it
|
|
|
|
/// - If it exists, look for config changes and sync them
|
|
|
|
/// - If it exists, look for config changes and sync them
|
|
|
|
pub fn open_system_database<Fs: RawFSInterface>(
|
|
|
|
pub fn open_system_database<Fs: RawFSInterface>(auth: ConfigAuth) -> SDSSResult<SystemStoreInit> {
|
|
|
|
auth: Option<ConfigAuth>,
|
|
|
|
|
|
|
|
) -> SDSSResult<SystemStoreInit> {
|
|
|
|
|
|
|
|
open_or_reinit_system_database::<Fs>(auth, SYSDB_PATH, SYSDB_COW_PATH)
|
|
|
|
open_or_reinit_system_database::<Fs>(auth, SYSDB_PATH, SYSDB_COW_PATH)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Open or re-initialize the system database
|
|
|
|
/// Open or re-initialize the system database
|
|
|
|
pub fn open_or_reinit_system_database<Fs: RawFSInterface>(
|
|
|
|
pub fn open_or_reinit_system_database<Fs: RawFSInterface>(
|
|
|
|
auth: Option<ConfigAuth>,
|
|
|
|
auth: ConfigAuth,
|
|
|
|
sysdb_path: &str,
|
|
|
|
sysdb_path: &str,
|
|
|
|
sysdb_path_cow: &str,
|
|
|
|
sysdb_path_cow: &str,
|
|
|
|
) -> SDSSResult<SystemStoreInit> {
|
|
|
|
) -> SDSSResult<SystemStoreInit> {
|
|
|
|
let (ex, _) = match SDSSFileIO::<Fs>::open_or_create_perm_rw::<spec::SysDBV1>(sysdb_path)? {
|
|
|
|
let sysdb_file = match SDSSFileIO::<Fs>::open_or_create_perm_rw::<spec::SysDBV1>(sysdb_path)? {
|
|
|
|
FileOpen::Created(new_sysdb) => {
|
|
|
|
FileOpen::Created(new) => {
|
|
|
|
let syscfg = SysConfig::new_auth(auth, SysHostData::new(0, 0));
|
|
|
|
// init new syscfg
|
|
|
|
sync_system_database_to(&syscfg, new_sysdb)?;
|
|
|
|
let new_syscfg = SysConfig::new_auth(auth);
|
|
|
|
return Ok(SystemStoreInit::new(syscfg, SystemStoreInitState::Created));
|
|
|
|
sync_system_database_to(&new_syscfg, new)?;
|
|
|
|
|
|
|
|
return Ok(SystemStoreInit::new(
|
|
|
|
|
|
|
|
new_syscfg,
|
|
|
|
|
|
|
|
SystemStoreInitState::Created,
|
|
|
|
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FileOpen::Existing(ex) => ex,
|
|
|
|
FileOpen::Existing((ex, _)) => ex,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
let last_syscfg = decode_system_database(ex)?;
|
|
|
|
let prev_sysdb = decode_system_database(sysdb_file)?;
|
|
|
|
let mut state = SystemStoreInitState::Unchanged;
|
|
|
|
let state;
|
|
|
|
match (last_syscfg.auth_data(), &auth) {
|
|
|
|
// see if settings have changed
|
|
|
|
(Some(last_auth), Some(new_auth)) => {
|
|
|
|
if prev_sysdb
|
|
|
|
let last_auth = last_auth.read();
|
|
|
|
.auth_data()
|
|
|
|
if last_auth.verify_user("root", &new_auth.root_key).is_err() {
|
|
|
|
.read()
|
|
|
|
// the root password was changed
|
|
|
|
.verify_user("root", &auth.root_key)
|
|
|
|
state = SystemStoreInitState::UpdatedRoot;
|
|
|
|
.is_ok()
|
|
|
|
}
|
|
|
|
{
|
|
|
|
}
|
|
|
|
state = SystemStoreInitState::Unchanged;
|
|
|
|
(Some(_), None) => {
|
|
|
|
} else {
|
|
|
|
state = SystemStoreInitState::UpdatedAuthDisabled;
|
|
|
|
state = SystemStoreInitState::UpdatedRoot;
|
|
|
|
}
|
|
|
|
|
|
|
|
(None, Some(_)) => {
|
|
|
|
|
|
|
|
state = SystemStoreInitState::UpdatedAuthEnabled;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
(None, None) => {}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let new_syscfg = SysConfig::new_auth(
|
|
|
|
// create new config
|
|
|
|
|
|
|
|
let new_syscfg = SysConfig::new_full(
|
|
|
|
auth,
|
|
|
|
auth,
|
|
|
|
SysHostData::new(
|
|
|
|
SysHostData::new(
|
|
|
|
last_syscfg.host_data().startup_counter() + 1,
|
|
|
|
prev_sysdb.host_data().startup_counter() + 1,
|
|
|
|
last_syscfg.host_data().settings_version()
|
|
|
|
prev_sysdb.host_data().settings_version()
|
|
|
|
+ !matches!(state, SystemStoreInitState::Unchanged) as u32,
|
|
|
|
+ !matches!(state, SystemStoreInitState::Unchanged) as u32,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
// sync
|
|
|
|
// sync
|
|
|
|
let cow_file = SDSSFileIO::<Fs>::create::<spec::SysDBV1>(sysdb_path_cow)?;
|
|
|
|
sync_system_database_to(
|
|
|
|
sync_system_database_to(&new_syscfg, cow_file)?;
|
|
|
|
&new_syscfg,
|
|
|
|
// replace
|
|
|
|
SDSSFileIO::<Fs>::create::<spec::SysDBV1>(sysdb_path_cow)?,
|
|
|
|
|
|
|
|
)?;
|
|
|
|
Fs::fs_rename_file(sysdb_path_cow, sysdb_path)?;
|
|
|
|
Fs::fs_rename_file(sysdb_path_cow, sysdb_path)?;
|
|
|
|
Ok(SystemStoreInit::new(new_syscfg, state))
|
|
|
|
Ok(SystemStoreInit::new(new_syscfg, state))
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -145,38 +140,29 @@ pub fn sync_system_database_to<Fs: RawFSInterface>(
|
|
|
|
SYS_KEY_AUTH => DictGeneric::new(),
|
|
|
|
SYS_KEY_AUTH => DictGeneric::new(),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
let auth_key = map.get_mut(SYS_KEY_AUTH).unwrap();
|
|
|
|
let auth_key = map.get_mut(SYS_KEY_AUTH).unwrap();
|
|
|
|
match cfg.auth_data() {
|
|
|
|
let auth = cfg.auth_data().read();
|
|
|
|
None => {
|
|
|
|
let auth_key = auth_key.as_dict_mut().unwrap();
|
|
|
|
*auth_key = DictEntryGeneric::Map(
|
|
|
|
auth_key.insert(
|
|
|
|
into_dict!(SYS_KEY_AUTH_ROOT => Datacell::null(), SYS_KEY_AUTH_USERS => Datacell::null()),
|
|
|
|
SYS_KEY_AUTH_ROOT.into(),
|
|
|
|
)
|
|
|
|
DictEntryGeneric::Data(Datacell::new_bin(auth.root_key().into())),
|
|
|
|
}
|
|
|
|
);
|
|
|
|
Some(auth) => {
|
|
|
|
auth_key.insert(
|
|
|
|
let auth = auth.read();
|
|
|
|
SYS_KEY_AUTH_USERS.into(),
|
|
|
|
let auth_key = auth_key.as_dict_mut().unwrap();
|
|
|
|
DictEntryGeneric::Map(
|
|
|
|
auth_key.insert(
|
|
|
|
// username -> [..settings]
|
|
|
|
SYS_KEY_AUTH_ROOT.into(),
|
|
|
|
auth.users()
|
|
|
|
DictEntryGeneric::Data(Datacell::new_bin(auth.root_key().into())),
|
|
|
|
.iter()
|
|
|
|
);
|
|
|
|
.map(|(username, user)| {
|
|
|
|
auth_key.insert(
|
|
|
|
(
|
|
|
|
SYS_KEY_AUTH_USERS.into(),
|
|
|
|
username.to_owned(),
|
|
|
|
DictEntryGeneric::Map(
|
|
|
|
DictEntryGeneric::Data(Datacell::new_list(vec![Datacell::new_bin(
|
|
|
|
// username -> [..settings]
|
|
|
|
user.key().into(),
|
|
|
|
auth.users()
|
|
|
|
)])),
|
|
|
|
.iter()
|
|
|
|
)
|
|
|
|
.map(|(username, user)| {
|
|
|
|
})
|
|
|
|
(
|
|
|
|
.collect(),
|
|
|
|
username.to_owned(),
|
|
|
|
),
|
|
|
|
DictEntryGeneric::Data(Datacell::new_list(vec![
|
|
|
|
);
|
|
|
|
Datacell::new_bin(user.key().into()),
|
|
|
|
|
|
|
|
])),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.collect(),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// write
|
|
|
|
// write
|
|
|
|
let buf = super::inf::enc::enc_dict_full::<super::inf::map::GenericDictSpec>(&map);
|
|
|
|
let buf = super::inf::enc::enc_dict_full::<super::inf::map::GenericDictSpec>(&map);
|
|
|
|
f.fsynced_write(&buf)
|
|
|
|
f.fsynced_write(&buf)
|
|
|
@ -195,59 +181,49 @@ fn rkey<T>(
|
|
|
|
|
|
|
|
|
|
|
|
/// Decode the system database
|
|
|
|
/// Decode the system database
|
|
|
|
pub fn decode_system_database<Fs: RawFSInterface>(mut f: SDSSFileIO<Fs>) -> SDSSResult<SysConfig> {
|
|
|
|
pub fn decode_system_database<Fs: RawFSInterface>(mut f: SDSSFileIO<Fs>) -> SDSSResult<SysConfig> {
|
|
|
|
let rem = f.load_remaining_into_buffer()?;
|
|
|
|
let mut sysdb_data =
|
|
|
|
let mut store = inf::dec::dec_dict_full::<inf::map::GenericDictSpec>(&rem)?;
|
|
|
|
inf::dec::dec_dict_full::<inf::map::GenericDictSpec>(&f.load_remaining_into_buffer()?)?;
|
|
|
|
// find auth and sys stores
|
|
|
|
// get our auth and sys stores
|
|
|
|
let mut auth_store = rkey(&mut store, SYS_KEY_AUTH, DictEntryGeneric::into_dict)?;
|
|
|
|
let mut auth_store = rkey(&mut sysdb_data, SYS_KEY_AUTH, DictEntryGeneric::into_dict)?;
|
|
|
|
let mut sys_store = rkey(&mut store, SYS_KEY_SYS, DictEntryGeneric::into_dict)?;
|
|
|
|
let mut sys_store = rkey(&mut sysdb_data, SYS_KEY_SYS, DictEntryGeneric::into_dict)?;
|
|
|
|
// get our auth
|
|
|
|
// load auth store
|
|
|
|
let auth_root = rkey(&mut auth_store, SYS_KEY_AUTH_ROOT, |dict| {
|
|
|
|
let root_key = rkey(&mut auth_store, SYS_KEY_AUTH_ROOT, |d| {
|
|
|
|
let data = dict.into_data()?;
|
|
|
|
d.into_data()?.into_bin()
|
|
|
|
match data.kind() {
|
|
|
|
|
|
|
|
_ if data.is_null() => Some(None),
|
|
|
|
|
|
|
|
_ => data.into_bin().map(Some),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})?;
|
|
|
|
})?;
|
|
|
|
let auth_users = rkey(&mut auth_store, SYS_KEY_AUTH_USERS, |dict| match dict {
|
|
|
|
let users = rkey(
|
|
|
|
DictEntryGeneric::Data(dc) if dc.is_null() => Some(None),
|
|
|
|
&mut auth_store,
|
|
|
|
DictEntryGeneric::Map(m) => Some(Some(m)),
|
|
|
|
SYS_KEY_AUTH_USERS,
|
|
|
|
_ => None,
|
|
|
|
DictEntryGeneric::into_dict,
|
|
|
|
})?;
|
|
|
|
)?;
|
|
|
|
let sys_auth = match (auth_root, auth_users) {
|
|
|
|
// load users
|
|
|
|
(Some(root_pass), Some(users)) => {
|
|
|
|
let mut loaded_users = HashMap::new();
|
|
|
|
let mut usermap = HashMap::new();
|
|
|
|
for (username, userdata) in users {
|
|
|
|
for (user_name, user) in users {
|
|
|
|
let mut userdata = userdata
|
|
|
|
let mut user_data = user
|
|
|
|
.into_data()
|
|
|
|
.into_data()
|
|
|
|
.and_then(Datacell::into_list)
|
|
|
|
.and_then(|d| d.into_list())
|
|
|
|
.ok_or(SDSSError::SysDBCorrupted)?;
|
|
|
|
.ok_or(SDSSError::SysDBCorrupted)?;
|
|
|
|
if userdata.len() != 1 {
|
|
|
|
if user_data.len() != 1 {
|
|
|
|
return Err(SDSSError::SysDBCorrupted);
|
|
|
|
return Err(SDSSError::SysDBCorrupted);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
let password = user_data
|
|
|
|
|
|
|
|
.remove(0)
|
|
|
|
|
|
|
|
.into_bin()
|
|
|
|
|
|
|
|
.ok_or(SDSSError::SysDBCorrupted)?;
|
|
|
|
|
|
|
|
usermap.insert(user_name, SysAuthUser::new(password.into_boxed_slice()));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(RwLock::new(SysAuth::new(
|
|
|
|
|
|
|
|
root_pass.into_boxed_slice(),
|
|
|
|
|
|
|
|
usermap,
|
|
|
|
|
|
|
|
)))
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(None, None) => None,
|
|
|
|
let user_password = userdata
|
|
|
|
_ => return Err(SDSSError::SysDBCorrupted),
|
|
|
|
.remove(0)
|
|
|
|
};
|
|
|
|
.into_bin()
|
|
|
|
// get our sys
|
|
|
|
.ok_or(SDSSError::SysDBCorrupted)?;
|
|
|
|
let sv = rkey(&mut sys_store, SYS_KEY_SYS_SETTINGS_VERSION, |de| {
|
|
|
|
loaded_users.insert(username, SysAuthUser::new(user_password.into_boxed_slice()));
|
|
|
|
de.into_data()?.into_uint()
|
|
|
|
}
|
|
|
|
|
|
|
|
let sys_auth = SysAuth::new(root_key.into_boxed_slice(), loaded_users);
|
|
|
|
|
|
|
|
// load sys data
|
|
|
|
|
|
|
|
let sc = rkey(&mut sys_store, SYS_KEY_SYS_STARTUP_COUNTER, |d| {
|
|
|
|
|
|
|
|
d.into_data()?.into_uint()
|
|
|
|
})?;
|
|
|
|
})?;
|
|
|
|
let sc = rkey(&mut sys_store, SYS_KEY_SYS_STARTUP_COUNTER, |de| {
|
|
|
|
let sv = rkey(&mut sys_store, SYS_KEY_SYS_SETTINGS_VERSION, |d| {
|
|
|
|
de.into_data()?.into_uint()
|
|
|
|
d.into_data()?.into_uint()
|
|
|
|
})?;
|
|
|
|
})?;
|
|
|
|
if !(sys_store.is_empty() & auth_store.is_empty() & store.is_empty()) {
|
|
|
|
if !(sysdb_data.is_empty() & auth_store.is_empty() & sys_store.is_empty()) {
|
|
|
|
// the stores have more keys than we expected. something is wrong here
|
|
|
|
|
|
|
|
return Err(SDSSError::SysDBCorrupted);
|
|
|
|
return Err(SDSSError::SysDBCorrupted);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(SysConfig::new(sys_auth, SysHostData::new(sc, sv as u32)))
|
|
|
|
Ok(SysConfig::new(
|
|
|
|
|
|
|
|
RwLock::new(sys_auth),
|
|
|
|
|
|
|
|
SysHostData::new(sc, sv as u32),
|
|
|
|
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
|
|
|