Fix issue where groupless users own all users/dbs #13
|
@ -137,14 +137,14 @@ async fn change_password_for_user(
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn show_users(args: UserShowArgs, conn: &mut MySqlConnection) -> anyhow::Result<()> {
|
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() {
|
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 {
|
} else {
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
for username in args.username {
|
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!("{}", e);
|
||||||
eprintln!("Skipping...");
|
eprintln!("Skipping...");
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -42,6 +42,26 @@ pub fn get_unix_groups(user: &User) -> anyhow::Result<Vec<Group>> {
|
||||||
Ok(groups)
|
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::<Vec<_>>()
|
||||||
|
.join("|")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn validate_prefix_for_user<'a>(name: &'a str, user: &User) -> anyhow::Result<&'a str> {
|
pub fn validate_prefix_for_user<'a>(name: &'a str, user: &User) -> anyhow::Result<&'a str> {
|
||||||
let user_groups = get_unix_groups(user)?;
|
let user_groups = get_unix_groups(user)?;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@ use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{mysql::MySqlRow, prelude::*, MySqlConnection};
|
use sqlx::{mysql::MySqlRow, prelude::*, MySqlConnection};
|
||||||
|
|
||||||
use super::common::{
|
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<()> {
|
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<Vec<String>> {
|
pub async fn get_database_list(conn: &mut MySqlConnection) -> anyhow::Result<Vec<String>> {
|
||||||
let unix_user = get_current_unix_user()?;
|
let unix_user = get_current_unix_user()?;
|
||||||
let unix_groups = get_unix_groups(&unix_user)?
|
|
||||||
.into_iter()
|
|
||||||
.map(|g| g.name)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let databases = sqlx::query_as::<_, DatabaseName>(
|
let databases = sqlx::query_as::<_, DatabaseName>(
|
||||||
r#"
|
r#"
|
||||||
|
@ -69,11 +66,7 @@ pub async fn get_database_list(conn: &mut MySqlConnection) -> anyhow::Result<Vec
|
||||||
AND `SCHEMA_NAME` REGEXP ?
|
AND `SCHEMA_NAME` REGEXP ?
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
.bind(format!(
|
.bind(create_user_group_matching_regex(&unix_user))
|
||||||
"({}|{})_.+",
|
|
||||||
unix_user.name,
|
|
||||||
unix_groups.iter().map(|g| g.to_string()).join("|")
|
|
||||||
))
|
|
||||||
.fetch_all(conn)
|
.fetch_all(conn)
|
||||||
.await
|
.await
|
||||||
.context(format!(
|
.context(format!(
|
||||||
|
@ -241,10 +234,6 @@ pub async fn get_all_database_privileges(
|
||||||
conn: &mut MySqlConnection,
|
conn: &mut MySqlConnection,
|
||||||
) -> anyhow::Result<Vec<DatabasePrivileges>> {
|
) -> anyhow::Result<Vec<DatabasePrivileges>> {
|
||||||
let unix_user = get_current_unix_user()?;
|
let unix_user = get_current_unix_user()?;
|
||||||
let unix_groups = get_unix_groups(&unix_user)?
|
|
||||||
.into_iter()
|
|
||||||
.map(|g| g.name)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let result = sqlx::query_as::<_, DatabasePrivileges>(&format!(
|
let result = sqlx::query_as::<_, DatabasePrivileges>(&format!(
|
||||||
indoc! {r#"
|
indoc! {r#"
|
||||||
|
@ -259,11 +248,7 @@ pub async fn get_all_database_privileges(
|
||||||
.map(|field| format!("`{field}`"))
|
.map(|field| format!("`{field}`"))
|
||||||
.join(","),
|
.join(","),
|
||||||
))
|
))
|
||||||
.bind(format!(
|
.bind(create_user_group_matching_regex(&unix_user))
|
||||||
"({}|{})_.+",
|
|
||||||
unix_user.name,
|
|
||||||
unix_groups.iter().map(|g| g.to_string()).join("|")
|
|
||||||
))
|
|
||||||
.fetch_all(conn)
|
.fetch_all(conn)
|
||||||
.await
|
.await
|
||||||
.context("Failed to show databases")?;
|
.context("Failed to show databases")?;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use sqlx::{prelude::*, MySqlConnection};
|
||||||
|
|
||||||
use crate::core::common::quote_literal;
|
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<()> {
|
pub async fn create_database_user(db_user: &str, conn: &mut MySqlConnection) -> anyhow::Result<()> {
|
||||||
let unix_user = get_current_unix_user()?;
|
let unix_user = get_current_unix_user()?;
|
||||||
|
@ -71,22 +71,10 @@ pub struct DatabaseUser {
|
||||||
pub authentication_string: String,
|
pub authentication_string: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_all_database_users_for_user(
|
pub async fn get_all_database_users_for_unix_user(
|
||||||
user: &User,
|
unix_user: &User,
|
||||||
conn: &mut MySqlConnection,
|
conn: &mut MySqlConnection,
|
||||||
) -> anyhow::Result<Vec<DatabaseUser>> {
|
) -> anyhow::Result<Vec<DatabaseUser>> {
|
||||||
let groups = get_unix_groups(user)?;
|
|
||||||
|
|
||||||
let regex = format!(
|
|
||||||
"({}|{})(_.+)?",
|
|
||||||
user.name,
|
|
||||||
groups
|
|
||||||
.iter()
|
|
||||||
.map(|g| g.name.as_str())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("|")
|
|
||||||
);
|
|
||||||
|
|
||||||
let users = sqlx::query_as::<_, DatabaseUser>(
|
let users = sqlx::query_as::<_, DatabaseUser>(
|
||||||
r#"
|
r#"
|
||||||
SELECT `User`, `Host`, `Password`, `authentication_string`
|
SELECT `User`, `Host`, `Password`, `authentication_string`
|
||||||
|
@ -94,7 +82,7 @@ pub async fn get_all_database_users_for_user(
|
||||||
WHERE `User` REGEXP ?
|
WHERE `User` REGEXP ?
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
.bind(regex)
|
.bind(create_user_group_matching_regex(unix_user))
|
||||||
.fetch_all(conn)
|
.fetch_all(conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue