From eddc0ad5e997a67369999f70371a3658ff6997a7 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Sun, 4 Aug 2024 14:29:34 +0200 Subject: [PATCH] Fix issue where groupless users own all users/dbs --- src/cli/user_command.rs | 6 +++--- src/core/common.rs | 20 ++++++++++++++++++++ src/core/database_operations.rs | 23 ++++------------------- src/core/user_operations.rs | 20 ++++---------------- 4 files changed, 31 insertions(+), 38 deletions(-) diff --git a/src/cli/user_command.rs b/src/cli/user_command.rs index 7005fb9..b17ee20 100644 --- a/src/cli/user_command.rs +++ b/src/cli/user_command.rs @@ -137,14 +137,14 @@ async fn change_password_for_user( } async fn show_users(args: UserShowArgs, conn: &mut MySqlConnection) -> anyhow::Result<()> { - let user = crate::core::common::get_current_unix_user()?; + let unix_user = crate::core::common::get_current_unix_user()?; let users = if args.username.is_empty() { - crate::core::user_operations::get_all_database_users_for_user(&user, conn).await? + crate::core::user_operations::get_all_database_users_for_unix_user(&unix_user, conn).await? } else { let mut result = vec![]; for username in args.username { - if let Err(e) = validate_ownership_of_user_name(&username, &user) { + if let Err(e) = validate_ownership_of_user_name(&username, &unix_user) { eprintln!("{}", e); eprintln!("Skipping..."); continue; diff --git a/src/core/common.rs b/src/core/common.rs index 6cf6974..2f7118d 100644 --- a/src/core/common.rs +++ b/src/core/common.rs @@ -42,6 +42,26 @@ pub fn get_unix_groups(user: &User) -> anyhow::Result> { Ok(groups) } +/// This function creates a regex that matches items (users, databases) +/// that belong to the user or any of the user's groups. +pub fn create_user_group_matching_regex(user: &User) -> String { + let groups = get_unix_groups(user).unwrap_or_default(); + + if groups.is_empty() { + format!("{}(_.+)?", user.name) + } else { + format!( + "({}|{})(_.+)?", + user.name, + groups + .iter() + .map(|g| g.name.as_str()) + .collect::>() + .join("|") + ) + } +} + pub fn validate_prefix_for_user<'a>(name: &'a str, user: &User) -> anyhow::Result<&'a str> { let user_groups = get_unix_groups(user)?; diff --git a/src/core/database_operations.rs b/src/core/database_operations.rs index 6b3ec11..9343988 100644 --- a/src/core/database_operations.rs +++ b/src/core/database_operations.rs @@ -8,7 +8,8 @@ use serde::{Deserialize, Serialize}; use sqlx::{mysql::MySqlRow, prelude::*, MySqlConnection}; use super::common::{ - get_current_unix_user, get_unix_groups, quote_identifier, validate_prefix_for_user, + create_user_group_matching_regex, get_current_unix_user, quote_identifier, + validate_prefix_for_user, }; pub async fn create_database(name: &str, conn: &mut MySqlConnection) -> anyhow::Result<()> { @@ -56,10 +57,6 @@ struct DatabaseName { pub async fn get_database_list(conn: &mut MySqlConnection) -> anyhow::Result> { let unix_user = get_current_unix_user()?; - let unix_groups = get_unix_groups(&unix_user)? - .into_iter() - .map(|g| g.name) - .collect::>(); let databases = sqlx::query_as::<_, DatabaseName>( r#" @@ -69,11 +66,7 @@ pub async fn get_database_list(conn: &mut MySqlConnection) -> anyhow::Result anyhow::Result> { let unix_user = get_current_unix_user()?; - let unix_groups = get_unix_groups(&unix_user)? - .into_iter() - .map(|g| g.name) - .collect::>(); let result = sqlx::query_as::<_, DatabasePrivileges>(&format!( indoc! {r#" @@ -259,11 +248,7 @@ pub async fn get_all_database_privileges( .map(|field| format!("`{field}`")) .join(","), )) - .bind(format!( - "({}|{})_.+", - unix_user.name, - unix_groups.iter().map(|g| g.to_string()).join("|") - )) + .bind(create_user_group_matching_regex(&unix_user)) .fetch_all(conn) .await .context("Failed to show databases")?; diff --git a/src/core/user_operations.rs b/src/core/user_operations.rs index 468ed85..0eefdad 100644 --- a/src/core/user_operations.rs +++ b/src/core/user_operations.rs @@ -6,7 +6,7 @@ use sqlx::{prelude::*, MySqlConnection}; use crate::core::common::quote_literal; -use super::common::{get_current_unix_user, get_unix_groups, validate_prefix_for_user}; +use super::common::{create_user_group_matching_regex, get_current_unix_user, validate_prefix_for_user}; pub async fn create_database_user(db_user: &str, conn: &mut MySqlConnection) -> anyhow::Result<()> { let unix_user = get_current_unix_user()?; @@ -71,22 +71,10 @@ pub struct DatabaseUser { pub authentication_string: String, } -pub async fn get_all_database_users_for_user( - user: &User, +pub async fn get_all_database_users_for_unix_user( + unix_user: &User, conn: &mut MySqlConnection, ) -> anyhow::Result> { - let groups = get_unix_groups(user)?; - - let regex = format!( - "({}|{})(_.+)?", - user.name, - groups - .iter() - .map(|g| g.name.as_str()) - .collect::>() - .join("|") - ); - let users = sqlx::query_as::<_, DatabaseUser>( r#" SELECT `User`, `Host`, `Password`, `authentication_string` @@ -94,7 +82,7 @@ pub async fn get_all_database_users_for_user( WHERE `User` REGEXP ? "#, ) - .bind(regex) + .bind(create_user_group_matching_regex(unix_user)) .fetch_all(conn) .await?;