mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 12:37:00 +01:00
20241017 unixd home (#3113)
This commit is contained in:
parent
5a3e5f1e07
commit
dc5f40d404
|
@ -54,8 +54,9 @@ version = '2'
|
||||||
|
|
||||||
# home_attr = "uuid"
|
# home_attr = "uuid"
|
||||||
|
|
||||||
# Controls the prefix that will be appended to the home alias when mounting home directories. Must
|
# Controls the prefix that will be prepended to the home name when using mounted home directories from
|
||||||
# end with a trailing `/`. If unset, defaults to the value of the `home_prefix`.
|
# a location that is outside of them `home_prefix`. Must end with a trailing `/`. If unset then home
|
||||||
|
# directories will be created in `home_prefix`.
|
||||||
#
|
#
|
||||||
# This is option is useful when implementing a networked home directory layout. A common implementation
|
# This is option is useful when implementing a networked home directory layout. A common implementation
|
||||||
# is to configure a networked filesystem that contains user directories mounted at `/u/` (eg /u/$user_uuid)
|
# is to configure a networked filesystem that contains user directories mounted at `/u/` (eg /u/$user_uuid)
|
||||||
|
@ -64,12 +65,19 @@ version = '2'
|
||||||
#
|
#
|
||||||
# > home_attr = "uuid"
|
# > home_attr = "uuid"
|
||||||
# > home_alias = "name"
|
# > home_alias = "name"
|
||||||
# > home_prefix = "/u/"
|
# > home_prefix = "/home/"
|
||||||
# > home_mount_prefix = "/home/"
|
# > home_mount_prefix = "/u/"
|
||||||
|
#
|
||||||
|
# ⚠️ If you expect directories to be created by kanidm unixd tasks in an alternate mount prefix, then
|
||||||
|
# you need to run `systemctl edit kanidm-unixd-tasks` to allow the daemon to write to these locations.
|
||||||
|
#
|
||||||
|
# > [Service]
|
||||||
|
# > ReadWritePaths=/home /var/run/kanidm-unixd /u
|
||||||
|
#
|
||||||
#
|
#
|
||||||
# Default: unset
|
# Default: unset
|
||||||
#
|
#
|
||||||
# home_mount_prefix = "/home/"
|
# home_mount_prefix = "/u/"
|
||||||
#
|
#
|
||||||
|
|
||||||
# The default token attribute used for generating symlinks pointing to the user's home
|
# The default token attribute used for generating symlinks pointing to the user's home
|
||||||
|
|
|
@ -97,12 +97,15 @@ fn create_home_directory(
|
||||||
// be possible, but we assert this to be sure.
|
// be possible, but we assert this to be sure.
|
||||||
let name = info.name.trim_start_matches('.').replace(['/', '\\'], "");
|
let name = info.name.trim_start_matches('.').replace(['/', '\\'], "");
|
||||||
|
|
||||||
let home_mount_prefix_path_is_set = home_mount_prefix_path.is_some();
|
debug!(?home_prefix_path, ?home_mount_prefix_path, ?info);
|
||||||
|
|
||||||
|
// This is where the users home dir "is" and aliases from here go to the true storage
|
||||||
|
// mounts
|
||||||
let home_prefix_path = home_prefix_path
|
let home_prefix_path = home_prefix_path
|
||||||
.canonicalize()
|
.canonicalize()
|
||||||
.map_err(|e| format!("{:?}", e))?;
|
.map_err(|e| format!("{:?}", e))?;
|
||||||
|
|
||||||
|
// This is where the storage is *mounted*. If not set, falls back to the home_prefix.
|
||||||
let home_mount_prefix_path = home_mount_prefix_path
|
let home_mount_prefix_path = home_mount_prefix_path
|
||||||
.unwrap_or(&home_prefix_path)
|
.unwrap_or(&home_prefix_path)
|
||||||
.canonicalize()
|
.canonicalize()
|
||||||
|
@ -120,27 +123,16 @@ fn create_home_directory(
|
||||||
return Err("Invalid home_mount_prefix from configuration - home_prefix path must exist, must be a directory, and must be absolute (not relative)".to_string());
|
return Err("Invalid home_mount_prefix from configuration - home_prefix path must exist, must be a directory, and must be absolute (not relative)".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actually process the request here.
|
// This is now creating the actual home directory in the home_mount path.
|
||||||
let hd_path = Path::join(&home_prefix_path, &name);
|
// First we want to validate that the path is legitimate and hasn't tried
|
||||||
|
// to escape the home_mount prefix.
|
||||||
// Assert the resulting named home path is consistent and correct. This is to ensure that
|
|
||||||
// the complete home path is not a path traversal outside of the home_prefixes.
|
|
||||||
if let Some(pp) = hd_path.parent() {
|
|
||||||
if pp != home_prefix_path {
|
|
||||||
return Err("Invalid home directory name - not within home_prefix".to_string());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err("Invalid/Corrupt home directory path - no prefix found".to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
let hd_mount_path = Path::join(&home_mount_prefix_path, &name);
|
let hd_mount_path = Path::join(&home_mount_prefix_path, &name);
|
||||||
|
|
||||||
|
debug!(?hd_mount_path);
|
||||||
|
|
||||||
if let Some(pp) = hd_mount_path.parent() {
|
if let Some(pp) = hd_mount_path.parent() {
|
||||||
if pp != home_mount_prefix_path {
|
if pp != home_mount_prefix_path {
|
||||||
return Err(
|
return Err("Invalid home directory name - not within home_mount_prefix".to_string());
|
||||||
"Invalid home directory name - not within home_prefix/home_mount_prefix"
|
|
||||||
.to_string(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err("Invalid/Corrupt home directory path - no prefix found".to_string());
|
return Err("Invalid/Corrupt home directory path - no prefix found".to_string());
|
||||||
|
@ -167,6 +159,7 @@ fn create_home_directory(
|
||||||
// Create the dir
|
// Create the dir
|
||||||
if let Err(e) = fs::create_dir_all(&hd_mount_path) {
|
if let Err(e) = fs::create_dir_all(&hd_mount_path) {
|
||||||
let _ = unsafe { umask(before) };
|
let _ = unsafe { umask(before) };
|
||||||
|
error!(err = ?e, ?hd_mount_path, "Unable to create directory");
|
||||||
return Err(format!("{:?}", e));
|
return Err(format!("{:?}", e));
|
||||||
}
|
}
|
||||||
let _ = unsafe { umask(before) };
|
let _ = unsafe { umask(before) };
|
||||||
|
@ -195,9 +188,15 @@ fn create_home_directory(
|
||||||
}
|
}
|
||||||
|
|
||||||
if entry.path().is_dir() {
|
if entry.path().is_dir() {
|
||||||
fs::create_dir_all(dest).map_err(|e| e.to_string())?;
|
fs::create_dir_all(dest).map_err(|e| {
|
||||||
|
error!(err = ?e, ?dest, "Unable to create directory from /etc/skel");
|
||||||
|
e.to_string()
|
||||||
|
})?;
|
||||||
} else {
|
} else {
|
||||||
fs::copy(entry.path(), dest).map_err(|e| e.to_string())?;
|
fs::copy(entry.path(), dest).map_err(|e| {
|
||||||
|
error!(err = ?e, ?dest, "Unable to copy from /etc/skel");
|
||||||
|
e.to_string()
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
chown(dest, info.gid)?;
|
chown(dest, info.gid)?;
|
||||||
|
|
||||||
|
@ -212,15 +211,6 @@ fn create_home_directory(
|
||||||
#[cfg(all(target_family = "unix", feature = "selinux"))]
|
#[cfg(all(target_family = "unix", feature = "selinux"))]
|
||||||
labeler.set_default_context_for_fs_objects()?;
|
labeler.set_default_context_for_fs_objects()?;
|
||||||
|
|
||||||
// If there is a mount prefix we use it, otherwise we use a relative path
|
|
||||||
// within the same directory.
|
|
||||||
let name_rel_path = if home_mount_prefix_path_is_set {
|
|
||||||
// Use the absolute path.
|
|
||||||
hd_mount_path.as_ref()
|
|
||||||
} else {
|
|
||||||
Path::new(&name)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Do the aliases exist?
|
// Do the aliases exist?
|
||||||
for alias in info.aliases.iter() {
|
for alias in info.aliases.iter() {
|
||||||
// Sanity check the alias.
|
// Sanity check the alias.
|
||||||
|
@ -239,9 +229,11 @@ fn create_home_directory(
|
||||||
}
|
}
|
||||||
|
|
||||||
if alias_path.exists() {
|
if alias_path.exists() {
|
||||||
|
debug!("checking symlink {:?} -> {:?}", alias_path, hd_mount_path);
|
||||||
let attr = match fs::symlink_metadata(&alias_path) {
|
let attr = match fs::symlink_metadata(&alias_path) {
|
||||||
Ok(a) => a,
|
Ok(a) => a,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
error!(err = ?e, ?alias_path, "Unable to read alias path metadata");
|
||||||
return Err(format!("{:?}", e));
|
return Err(format!("{:?}", e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -249,22 +241,27 @@ fn create_home_directory(
|
||||||
if attr.file_type().is_symlink() {
|
if attr.file_type().is_symlink() {
|
||||||
// Probably need to update it.
|
// Probably need to update it.
|
||||||
if let Err(e) = fs::remove_file(&alias_path) {
|
if let Err(e) = fs::remove_file(&alias_path) {
|
||||||
|
error!(err = ?e, ?alias_path, "Unable to remove existing alias path");
|
||||||
return Err(format!("{:?}", e));
|
return Err(format!("{:?}", e));
|
||||||
}
|
}
|
||||||
if let Err(e) = symlink(name_rel_path, &alias_path) {
|
|
||||||
|
debug!("updating symlink {:?} -> {:?}", alias_path, hd_mount_path);
|
||||||
|
if let Err(e) = symlink(&hd_mount_path, &alias_path) {
|
||||||
|
error!(err = ?e, ?alias_path, "Unable to update alias path");
|
||||||
return Err(format!("{:?}", e));
|
return Err(format!("{:?}", e));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
warn!(
|
warn!(
|
||||||
?alias_path,
|
?alias_path,
|
||||||
?alias,
|
?hd_mount_path,
|
||||||
?name,
|
"home directory alias path is not a symlink, unable to update"
|
||||||
"home directory alias is not a symlink, unable to update"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Does not exist. Create.
|
// Does not exist. Create.
|
||||||
if let Err(e) = symlink(name_rel_path, alias_path) {
|
debug!("creating symlink {:?} -> {:?}", alias_path, hd_mount_path);
|
||||||
|
if let Err(e) = symlink(&hd_mount_path, &alias_path) {
|
||||||
|
error!(err = ?e, ?alias_path, "Unable to create alias path");
|
||||||
return Err(format!("{:?}", e));
|
return Err(format!("{:?}", e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue