1 Commits

Author SHA1 Message Date
3f89eab11a WIP 2026-01-09 19:48:17 +09:00
19 changed files with 169 additions and 218 deletions

90
Cargo.lock generated
View File

@@ -292,9 +292,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.54"
version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
dependencies = [
"clap_builder",
"clap_derive",
@@ -313,9 +313,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.54"
version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
dependencies = [
"anstream",
"anstyle",
@@ -325,9 +325,9 @@ dependencies = [
[[package]]
name = "clap_complete"
version = "4.5.65"
version = "4.5.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "430b4dc2b5e3861848de79627b2bedc9f3342c7da5173a14eaa5d0f8dc18ae5d"
checksum = "004eef6b14ce34759aa7de4aea3217e368f463f46a3ed3764ca4b5a4404003b4"
dependencies = [
"clap",
"clap_lex",
@@ -353,6 +353,16 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
[[package]]
name = "clap_mangen"
version = "0.2.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ea63a92086df93893164221ad4f24142086d535b3a0957b9b9bea2dc86301"
dependencies = [
"clap",
"roff",
]
[[package]]
name = "color-print"
version = "0.3.7"
@@ -695,7 +705,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -1102,9 +1112,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.13.0"
version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
dependencies = [
"equivalent",
"hashbrown 0.16.1",
@@ -1127,7 +1137,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
dependencies = [
"hermit-abi",
"libc",
"windows-sys 0.52.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -1156,9 +1166,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.17"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
checksum = "7ee5b5339afb4c41626dde77b7a611bd4f2c202b897852b4bcf5d03eddc61010"
[[package]]
name = "jobserver"
@@ -1202,9 +1212,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.180"
version = "0.2.178"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
[[package]]
name = "libgit2-sys"
@@ -1337,6 +1347,7 @@ dependencies = [
"clap",
"clap-verbosity-flag",
"clap_complete",
"clap_mangen",
"color-print",
"const_format",
"derive_more",
@@ -1616,18 +1627,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.105"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.43"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [
"proc-macro2",
]
@@ -1769,6 +1780,12 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "roff"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3"
[[package]]
name = "rsa"
version = "0.9.9"
@@ -1808,7 +1825,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -1914,9 +1931,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.149"
version = "1.0.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da"
dependencies = [
"indexmap",
"itoa",
@@ -1992,11 +2009,10 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook-registry"
version = "1.4.8"
version = "1.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad"
dependencies = [
"errno",
"libc",
]
@@ -2275,9 +2291,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.114"
version = "2.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
dependencies = [
"proc-macro2",
"quote",
@@ -2305,7 +2321,7 @@ dependencies = [
"getrandom 0.3.4",
"once_cell",
"rustix",
"windows-sys 0.52.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -2395,9 +2411,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.49.0"
version = "1.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
dependencies = [
"bytes",
"libc",
@@ -2437,9 +2453,9 @@ dependencies = [
[[package]]
name = "tokio-stream"
version = "0.1.18"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70"
checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
dependencies = [
"futures-core",
"pin-project-lite",
@@ -2448,9 +2464,9 @@ dependencies = [
[[package]]
name = "tokio-util"
version = "0.7.18"
version = "0.7.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594"
dependencies = [
"bytes",
"futures-core",
@@ -2462,9 +2478,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.9.11+spec-1.1.0"
version = "0.9.10+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46"
checksum = "0825052159284a1a8b4d6c0c86cbc801f2da5afd2b225fa548c72f2e74002f48"
dependencies = [
"indexmap",
"serde_core",
@@ -3222,9 +3238,9 @@ dependencies = [
[[package]]
name = "zmij"
version = "1.0.10"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30e0d8dffbae3d840f64bda38e28391faef673a7b5a6017840f2a106c8145868"
checksum = "0f4a4e8e9dc5c62d159f04fcdbe07f4c3fb710415aab4754bf11505501e3251d"
[[package]]
name = "zstd"

View File

@@ -1,11 +1,12 @@
[package]
name = "muscl"
version = "1.0.0"
version = "0.1.0"
edition = "2024"
resolver = "2"
license = "BSD-3-Clause"
authors = [
"Programvareverkstedet <projects@pvv.ntnu.no>",
"oysteikt@pvv.ntnu.no",
"felixalb@pvv.ntnu.no",
]
homepage = "https://git.pvv.ntnu.no/Projects/muscl"
repository = "https://git.pvv.ntnu.no/Projects/muscl"
@@ -21,9 +22,10 @@ autolib = false
anyhow = "1.0.100"
async-bincode = "0.8.0"
bincode = "2.0.1"
clap = { version = "4.5.54", features = ["cargo", "derive"] }
clap = { version = "4.5.53", features = ["cargo", "derive"] }
clap-verbosity-flag = { version = "3.0.4", features = [ "tracing" ] }
clap_complete = { version = "4.5.65", features = ["unstable-dynamic"] }
clap_complete = { version = "4.5.62", features = ["unstable-dynamic"] }
clap_mangen = "0.2.31"
color-print = "0.3.7"
const_format = "0.2.35"
derive_more = { version = "2.1.1", features = ["display", "error"] }
@@ -37,14 +39,14 @@ num_cpus = "1.17.0"
prettytable = "0.10.0"
rand = "0.9.2"
serde = "1.0.228"
serde_json = { version = "1.0.149", features = ["preserve_order"] }
serde_json = { version = "1.0.148", features = ["preserve_order"] }
sqlx = { version = "0.8.6", features = ["runtime-tokio", "mysql", "tls-rustls"] }
thiserror = "2.0.17"
tokio = { version = "1.49.0", features = ["rt-multi-thread", "macros", "signal"] }
tokio = { version = "1.48.0", features = ["rt-multi-thread", "macros", "signal"] }
tokio-serde = { version = "0.9.0", features = ["bincode"] }
tokio-stream = "0.1.18"
tokio-util = { version = "0.7.18", features = ["codec", "rt"] }
toml = "0.9.11"
tokio-stream = "0.1.17"
tokio-util = { version = "0.7.17", features = ["codec", "rt"] }
toml = "0.9.10"
tracing = { version = "0.1.44", features = ["log"] }
tracing-subscriber = "0.3.22"
uuid = { version = "1.19.0", features = ["v4"] }

View File

@@ -47,8 +47,7 @@ over a IPC, which then performs the requested operations on behalf of the client
## Documentation
- [Installation and initial configuration](docs/installation.md)
- [Administration and further configuration](docs/administration.md)
- [Installation and configuration](docs/installation.md)
- [Development and testing](docs/development.md)
- [Compiling and packaging](docs/compiling.md)
- [Compatibility mode with mysql-admutils](docs/mysql-admutils-compatibility.md)

View File

@@ -1,5 +1,5 @@
# These are the default system groups on debian.
# You can also add groups by gid by prefixing the line with 'gid:'.
# You can alos add groups by gid by prefixing the line with 'gid:'.
group:_ssh
group:adm

View File

@@ -8,7 +8,7 @@ Type=notify
ExecStart=/usr/bin/muscl-server --systemd --disable-landlock socket-activate
ExecReload=/usr/bin/kill -HUP $MAINPID
WatchdogSec=3min
WatchdogSec=15
# Although this is a multi-instance unit, the constant `User` field is needed
# for authentication via mysql's auth_socket plugin to work.
@@ -61,7 +61,3 @@ SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources
UMask=0777
[Install]
Also=muscl.socket
WantedBy=multi-user.target

View File

@@ -3,7 +3,6 @@ Description=Muscl MySQL admin tool
[Socket]
ListenStream=/run/muscl/muscl.sock
RemoveOnStop=true
Accept=no
PassCredentials=true

View File

@@ -1,90 +0,0 @@
# Administration and further configuration
This page describes some additional configuration options and administration tasks for muscl.
## Configuring group denylists
In `/etc/muscl/muscl.conf`, you will find an option below `[authorization]` named `group_denylist_file`,
which points to `/etc/muscl/group_denylist.txt` by default.
In this file, you can add unix group names or GIDs to disallow the groups from being used as prefixes.
The deb package comes with a default denylist that disallows some common system groups.
The format of the file is one group name or GID per line. Lines starting with `#` and empty lines are ignored.
```
# Disallow using the 'root' group as a prefix
gid:0
# Disallow using the 'adm' group as a prefix
group:adm
```
> [!NOTE]
> If a user is named the same as a disallowed group, that user will still be able to use their username as a prefix.
## Configuring logging
By default, muscl logs to the systemd journal when run as a systemd service,
and also limits the log level to `info`. You can request more verbose logging
by appending `-v` flags to the `ExecStart=` line in the systemd service file.
To do this on a system where muscl was installed using a package, you can override
the service like this:
```bash
sudo systemctl edit muscl.service
```
This will open an editor where you can add the following lines:
```ini
[Service]
ExecStart=
ExecStart=/usr/bin/muscl-server -v ...
```
> [!NOTE]
> The first `ExecStart=` line is necessary to clear the previous value, as systemd
> interprets multiple `ExecStart=` lines as a list of commands to run in sequence.
You set either `-v` or `-vv` for `debug` and `trace` logging, respectively.
> [!WARNING]
> Be careful when enabling trace logging on production systems, as it might log
> passwords and credentials in plaintext.
## Querying logs in the systemd journal
Although invisible if you just run `journalctl -u muscl.service`, muscl adds a set of so-called
"fields" to its log entries to make it easier to filter and search them.
Here are some examples of how you can filter logs using `journalctl`:
```bash
# Show only logs related to a specific user
journalctl -eu muscl F_USER="<username>"
journalctl -eu muscl F_USER=johndoe
# Show only logs for a specific command types
journalctl -eu muscl F_COMMAND="<operation>"
journalctl -eu muscl F_COMMAND=create-db
# Show logs emitted for a specific session id
journalctl -eu muscl F_SESSION_ID="<session-id>"
journalctl -eu muscl F_SESSION_ID=123
# Show all of these fields together with the log message in a json format
journalctl --output json-pretty --output-fields MESSAGE,F_USER,F_COMMAND,F_SESSION_ID -eu muscl
```
See [`journalctl(1)`][journalctl_1] and [`systemd.journal-fields(7)`][systemd_journal-fields_7] for more information.
> [!NOTE]
> Please note that the commands are not 1-1 mapped to muscl subcommands.
> Rather, they are the available requests in the protocol used between the muscl client and server.
> These requests will often have the same name as the subcommands, but this is not always the case.
[journalctl_1]: https://man7.org/linux/man-pages/man1/journalctl.1.html
[systemd_journal-fields_7]: https://man7.org/linux/man-pages/man7/systemd.journal-fields.7.html

View File

@@ -39,12 +39,7 @@ docker stop mariadb
## Development using Nix
> [!NOTE]
> We have created some nix code to generate a QEMU VM with a setup similar to a production deployment
> There is not necessarily any VMs running in a production setup, and if so then at least not this VM.
> It is mainly there for easy access to interactive testing, as well as for testing the NixOS module.
If you have nix installed, you can easily test your changes in a NixOS test VM by running:
If you have nix installed, you can easily test your changes in a NixOS vm by running:
```bash
nix run .#vm # Start a NixOS VM in QEMU with muscl and MariaDB installed
@@ -52,3 +47,11 @@ nix run .#vm-mysql # Start a NixOS VM in QEMU with muscl and MySQL installed
```
You can configure the vm in `flake.nix`
## Filter logs by user with journalctl
If you want to filter the server logs by user, you can use journalctl's built-in filtering capabilities.
```bash
journalctl -eu muscl F_USER=<username>
```

View File

@@ -1,11 +1,9 @@
# Installation and initial configuration
# Installation and configuration
This document contains instructions for the recommended way of installing and configuring muscl.
Note that there are separate instructions for [installing on NixOS](nixos.md) and [installing with SUID/SGID mode](suid-sgid-mode.md).
After installation, you might want to look at the [Administration and further configuration](administration.md) page.
## Installing with deb on Debian
You can install muscl by adding the [PVV apt repository][pvv-apt-repository] and installing the package:
@@ -105,6 +103,28 @@ If you are using systemd, you should also create an override to unset the `Impor
ImportCredential=
```
## Configuring group denylists
In `/etc/muscl/muscl.conf`, you will find an option below `[authorization]` named `group_denylist_file`,
which points to `/etc/muscl/group_denylist.txt` by default.
In this file, you can add unix group names or GIDs to disallow the groups from being used as prefixes.
The deb package comes with a default denylist that disallows some common system groups.
The format of the file is one group name or GID per line. Lines starting with `#` and empty lines are ignored.
```
# Disallow using the 'root' group as a prefix
gid:0
# Disallow using the 'adm' group as a prefix
group:adm
```
> [!NOTE]
> If a user is named the same as a disallowed group, that user will still be able to use their username as a prefix.
## A note on minimum version requirements
The muscl server will work with older versions of systemd, but the recommended version is 254 or newer.

View File

@@ -4,8 +4,8 @@
> This will be deprecated in a future release, see https://git.pvv.ntnu.no/Projects/muscl/issues/101
>
> We do not recommend you use this mode unless you absolutely have to. The biggest reason why `muscl` was rewritten from scratch
> was to fix an architectural issue that easily caused vulnerabilities due to reliance on SUID/SGID. Although the architecture now
> is more resistant against such vulnerabilities, it is not failsafe.
> was to fix an architectural issue that easily caused vulnerabilites due to reliance on SUID/SGID. Althought the architecture now
> is more resistant against such vulnerabilites, it is not failsafe.
For backwards compatibility reasons, it is possible to run the program without a daemon by utilizing SUID/SGID.

18
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": {
"crane": {
"locked": {
"lastModified": 1767744144,
"narHash": "sha256-9/9ntI0D+HbN4G0TrK3KmHbTvwgswz7p8IEJsWyef8Q=",
"lastModified": 1766774972,
"narHash": "sha256-8qxEFpj4dVmIuPn9j9z6NTbU+hrcGjBOvaxTzre5HmM=",
"owner": "ipetkov",
"repo": "crane",
"rev": "2fb033290bf6b23f226d4c8b32f7f7a16b043d7e",
"rev": "01bc1d404a51a0a07e9d8759cd50a7903e218c82",
"type": "github"
},
"original": {
@@ -17,11 +17,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1768127708,
"narHash": "sha256-1Sm77VfZh3mU0F5OqKABNLWxOuDeHIlcFjsXeeiPazs=",
"lastModified": 1766902085,
"narHash": "sha256-coBu0ONtFzlwwVBzmjacUQwj3G+lybcZ1oeNSQkgC0M=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ffbc9f8cbaacfb331b6017d5a5abb21a492c9a38",
"rev": "c0b0e0fddf73fd517c3471e546c0df87a42d53f4",
"type": "github"
},
"original": {
@@ -45,11 +45,11 @@
]
},
"locked": {
"lastModified": 1768186348,
"narHash": "sha256-nkpIe3zkpeoFuOl8xBpexulECsHLQ9Ljg1gW3bPCjSI=",
"lastModified": 1766976750,
"narHash": "sha256-w+o3AIBI56tzfMJRqRXg9tSXnpQRN5hAT15o2t9rxYw=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "af69e497567a5945a64057717bc9b17c8478097e",
"rev": "9fe44e7f05b734a64a01f92fc51ad064fb0a884f",
"type": "github"
},
"original": {

View File

@@ -155,14 +155,15 @@ in
systemd.services."muscl" = {
reloadTriggers = [ config.environment.etc."muscl/config.toml".source ];
serviceConfig = {
Type = "notify-reload";
ExecStart = [
""
"${lib.getExe' cfg.package "muscl-server"} ${cfg.logLevel} --systemd --disable-landlock socket-activate"
];
ExecReload = "";
ReloadSignal = "SIGHUP";
ExecReload = [
""
"${lib.getExe' pkgs.coreutils "kill"} -HUP $MAINPID"
];
RuntimeDirectory = "muscl/root-mnt";
RuntimeDirectoryMode = "0700";

View File

@@ -54,13 +54,11 @@ for variant in debian-bookworm debian-trixie ubuntu-jammy ubuntu-noble; do
DEB_VERSION=$(find "$TMPDIR/muscl-deb-$variant-$GIT_SHA"/*.deb -print0 | xargs -0 -n1 basename | cut -d'_' -f2 | head -n1)
DEB_ARCH=$(find "$TMPDIR/muscl-deb-$variant-$GIT_SHA"/*.deb -print0 | xargs -0 -n1 basename | cut -d'_' -f3 | cut -d'.' -f1 | head -n1)
echo "[DELETE] https://git.pvv.ntnu.no/api/packages/Projects/debian/pool/$DISTRO_VERSION_NAME/main/$DEB_NAME/$DEB_VERSION/$DEB_ARCH"
curl \
-X DELETE \
--user "$GITEA_USER:$GITEA_TOKEN" \
"https://git.pvv.ntnu.no/api/packages/Projects/debian/pool/$DISTRO_VERSION_NAME/main/$DEB_NAME/$DEB_VERSION/$DEB_ARCH"
echo "[PUT] https://git.pvv.ntnu.no/api/packages/Projects/debian/pool/$DISTRO_VERSION_NAME/main/upload"
curl \
-X PUT \
--user "$GITEA_USER:$GITEA_TOKEN" \

View File

@@ -305,6 +305,10 @@ fn main() -> anyhow::Result<()> {
return Ok(());
}
if handle_manpage_command()?.is_some() {
return Ok(());
}
#[cfg(feature = "mysql-admutils-compatibility")]
if handle_mysql_admutils_command()?.is_some() {
return Ok(());
@@ -319,8 +323,7 @@ fn main() -> anyhow::Result<()> {
#[cfg(not(feature = "suid-sgid-mode"))]
None,
args.verbose,
)
.context("Failed to connect to the server")?;
)?;
tokio_run_command(args.command, connection)?;
@@ -362,6 +365,48 @@ fn handle_dynamic_completion() -> anyhow::Result<Option<()>> {
}
}
/// **WARNING:** This function may be run with elevated privileges.
fn handle_manpage_command() -> anyhow::Result<Option<()>> {
let argv1: Option<String> = std::env::args().nth(1);
match argv1.as_deref() {
Some("generate-manpages") => {
#[cfg(feature = "suid-sgid-mode")]
if executing_in_suid_sgid_mode()? {
use muscl_lib::core::bootstrap::drop_privs;
drop_privs()?
}
let output_dir = std::env::args().nth(2).ok_or(anyhow::anyhow!(
"Output directory argument missing for manpage generation"
))?;
let output_dir = PathBuf::from(&output_dir);
if !output_dir.is_dir() {
anyhow::bail!(
"Output directory `{:?}` does not exist or is not a directory",
output_dir,
);
}
let mut roff = clap_mangen::roff::Roff::new();
let man = clap_mangen::Man::new(Args::command());
man.render_title(&mut std::io::stdout())?;
man.render_name_section(&mut std::io::stdout())?;
man.render_synopsis_section(&mut std::io::stdout())?;
man.render_subcommands_section(&mut std::io::stdout())?;
man.render_options_section(&mut std::io::stdout())?;
roff.control("SH", ["VERSION"]);
roff.text([clap_mangen::roff::roman(AFTER_LONG_HELP)]);
roff.to_writer(&mut std::io::stdout())?;
Ok(Some(()))
}
_ => Ok(None),
}
}
/// **WARNING:** This function may be run with elevated privileges.
fn handle_mysql_admutils_command() -> anyhow::Result<Option<()>> {
let argv0 = std::env::args().next().and_then(|s| {
@@ -377,7 +422,7 @@ fn handle_mysql_admutils_command() -> anyhow::Result<Option<()>> {
}
}
/// Run the given command (from the client side) using Tokio.
/// Run the given commmand (from the client side) using Tokio.
fn tokio_run_command(
command: ClientCommand,
server_connection: StdUnixStream,

View File

@@ -35,7 +35,7 @@ spawn the editor stored in the $EDITOR environment variable.
(pico will be used if the variable is unset)
The file should contain one line per user, starting with the
username and followed by ten Y/N-values separated by whitespace.
username and followed by ten Y/N-values seperated by whitespace.
Lines starting with # are ignored.
The Y/N-values corresponds to the following mysql privileges:

View File

@@ -1,6 +1,5 @@
use std::{
fs,
os::unix::fs::FileTypeExt,
path::{Path, PathBuf},
sync::Arc,
time::Duration,
@@ -8,10 +7,7 @@ use std::{
use anyhow::{Context, anyhow};
use clap_verbosity_flag::{InfoLevel, Verbosity};
use nix::{
libc::{EXIT_SUCCESS, exit},
unistd::{AccessFlags, access},
};
use nix::libc::{EXIT_SUCCESS, exit};
use sqlx::mysql::MySqlPoolOptions;
use std::os::unix::net::UnixStream as StdUnixStream;
use tokio::{net::UnixStream as TokioUnixStream, sync::RwLock};
@@ -134,28 +130,11 @@ pub fn bootstrap_server_connection_and_drop_privileges(
}
}
fn socket_path_is_ok(path: &Path) -> anyhow::Result<()> {
fs::metadata(path)
.context(format!("Failed to get metadata for {:?}", path))
.and_then(|meta| {
if !meta.file_type().is_socket() {
anyhow::bail!("{:?} is not a unix socket", path);
}
access(path, AccessFlags::R_OK | AccessFlags::W_OK)
.with_context(|| format!("Socket at {:?} is not readable/writable", path))?;
Ok(())
})
}
fn connect_to_external_server(
server_socket_path: Option<PathBuf>,
) -> anyhow::Result<StdUnixStream> {
// TODO: ensure this is both readable and writable
if let Some(socket_path) = server_socket_path {
tracing::trace!("Checking socket at {:?}", socket_path);
socket_path_is_ok(&socket_path)?;
tracing::debug!("Connecting to socket at {:?}", socket_path);
return match StdUnixStream::connect(socket_path) {
Ok(socket) => Ok(socket),
@@ -168,9 +147,6 @@ fn connect_to_external_server(
}
if fs::metadata(DEFAULT_SOCKET_PATH).is_ok() {
tracing::trace!("Checking socket at {:?}", DEFAULT_SOCKET_PATH);
socket_path_is_ok(Path::new(DEFAULT_SOCKET_PATH))?;
tracing::debug!("Connecting to default socket at {:?}", DEFAULT_SOCKET_PATH);
return match StdUnixStream::connect(DEFAULT_SOCKET_PATH) {
Ok(socket) => Ok(socket),
@@ -182,9 +158,7 @@ fn connect_to_external_server(
};
}
anyhow::bail!(
"No socket path provided, and no socket found found at default location {DEFAULT_SOCKET_PATH}"
);
anyhow::bail!("No socket path provided, and no default socket found");
}
// TODO: this function is security critical, it should be integration tested

View File

@@ -100,7 +100,7 @@ impl UnixUser {
})
}
// pub fn from_environment() -> anyhow::Result<Self> {
// pub fn from_enviroment() -> anyhow::Result<Self> {
// let libc_uid = nix::unistd::getuid();
// UnixUser::from_uid(libc_uid.as_raw())
// }

View File

@@ -59,10 +59,6 @@ fn parse_group_denylist(denylist_path: &Path, lines: Lines) -> GroupDenylist {
}
.trim();
if trimmed_line.is_empty() {
continue;
}
let parts: Vec<&str> = trimmed_line.splitn(2, ':').collect();
if parts.len() != 2 {
tracing::warn!(

View File

@@ -140,7 +140,7 @@ impl Supervisor {
let (tx, rx) = broadcast::channel(1);
// TODO: try to detect systemd socket before using the provided socket path
// TODO: try to detech systemd socket before using the provided socket path
#[cfg(target_os = "linux")]
let listener = Arc::new(RwLock::new(match config.socket_path {
Some(ref path) => create_unix_listener_with_socket_path(path.clone()).await?,
@@ -295,15 +295,7 @@ impl Supervisor {
pub async fn reload(&self) -> anyhow::Result<()> {
#[cfg(target_os = "linux")]
sd_notify::notify(
false,
&[
sd_notify::NotifyState::Reloading,
sd_notify::NotifyState::monotonic_usec_now()
.expect("Failed to get monotonic time to send to systemd while reloading"),
sd_notify::NotifyState::Status("Reloading configuration"),
],
)?;
sd_notify::notify(false, &[sd_notify::NotifyState::Reloading])?;
let previous_config = self.config.lock().await.clone();
self.reload_config().await?;