From a7e9f39c40707edcff1edd603a680d707eca6bc2 Mon Sep 17 00:00:00 2001 From: alxndrv <44431221+alxndrv@users.noreply.github.com> Date: Tue, 18 Mar 2025 19:50:06 +0200 Subject: [PATCH] Implement `mcookie` --- Cargo.lock | 72 ++++++++++++++++++++++ Cargo.toml | 3 + src/uu/mcookie/Cargo.toml | 17 ++++++ src/uu/mcookie/mcookie.md | 7 +++ src/uu/mcookie/src/main.rs | 1 + src/uu/mcookie/src/mcookie.rs | 111 ++++++++++++++++++++++++++++++++++ 6 files changed, 211 insertions(+) create mode 100644 src/uu/mcookie/Cargo.toml create mode 100644 src/uu/mcookie/mcookie.md create mode 100644 src/uu/mcookie/src/main.rs create mode 100644 src/uu/mcookie/src/mcookie.rs diff --git a/Cargo.lock b/Cargo.lock index a2370b4..0c701f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,6 +88,15 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.17.0" @@ -240,6 +249,16 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "deranged" version = "0.3.11" @@ -255,6 +274,16 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dns-lookup" version = "2.0.4" @@ -295,6 +324,16 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.3.1" @@ -404,6 +443,16 @@ version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.7.4" @@ -916,6 +965,12 @@ dependencies = [ "time-core", ] +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + [[package]] name = "unicode-ident" version = "1.0.16" @@ -975,6 +1030,7 @@ dependencies = [ "uu_lscpu", "uu_lslocks", "uu_lsmem", + "uu_mcookie", "uu_mesg", "uu_mountpoint", "uu_renice", @@ -1068,6 +1124,16 @@ dependencies = [ "uucore", ] +[[package]] +name = "uu_mcookie" +version = "0.0.1" +dependencies = [ + "clap", + "md-5", + "rand 0.9.0", + "uucore", +] + [[package]] name = "uu_mesg" version = "0.0.1" @@ -1149,6 +1215,12 @@ version = "0.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb6d972f580f8223cb7052d8580aea2b7061e368cf476de32ea9457b19459ed" +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "wasi" version = "0.13.3+wasi-0.2.2" diff --git a/Cargo.toml b/Cargo.toml index de7e7bf..5bad5d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ feat_common_core = [ "lscpu", "lslocks", "lsmem", + "mcookie", "mesg", "mountpoint", "renice", @@ -48,6 +49,7 @@ clap_mangen = "0.2" dns-lookup = "2.0.4" libc = "0.2.152" linux-raw-sys = { version = "0.9.0", features = ["ioctl"] } +md-5 = "0.10.6" nix = { version = "0.29", default-features = false } phf = "0.11.2" phf_codegen = "0.11.2" @@ -81,6 +83,7 @@ last = { optional = true, version = "0.0.1", package = "uu_last", path = "src/uu lscpu = { optional = true, version = "0.0.1", package = "uu_lscpu", path = "src/uu/lscpu" } lslocks = { optional = true, version = "0.0.1", package = "uu_lslocks", path = "src/uu/lslocks" } lsmem = { optional = true, version = "0.0.1", package = "uu_lsmem", path = "src/uu/lsmem" } +mcookie = { optional = true, version = "0.0.1", package = "uu_mcookie", path = "src/uu/mcookie" } mesg = { optional = true, version = "0.0.1", package = "uu_mesg", path = "src/uu/mesg" } mountpoint = { optional = true, version = "0.0.1", package = "uu_mountpoint", path = "src/uu/mountpoint" } renice = { optional = true, version = "0.0.1", package = "uu_renice", path = "src/uu/renice" } diff --git a/src/uu/mcookie/Cargo.toml b/src/uu/mcookie/Cargo.toml new file mode 100644 index 0000000..6b5908e --- /dev/null +++ b/src/uu/mcookie/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "uu_mcookie" +version = "0.0.1" +edition = "2021" + +[lib] +path = "src/mcookie.rs" + +[[bin]] +name = "mcookie" +path = "src/main.rs" + +[dependencies] +uucore = { workspace = true } +clap = { workspace = true } +md-5 = { workspace = true } +rand = { workspace = true } diff --git a/src/uu/mcookie/mcookie.md b/src/uu/mcookie/mcookie.md new file mode 100644 index 0000000..22a6c90 --- /dev/null +++ b/src/uu/mcookie/mcookie.md @@ -0,0 +1,7 @@ +# mcookie + +``` +mcookie [OPTION]... +``` + +Generate magic cookies for xauth. diff --git a/src/uu/mcookie/src/main.rs b/src/uu/mcookie/src/main.rs new file mode 100644 index 0000000..453a0fd --- /dev/null +++ b/src/uu/mcookie/src/main.rs @@ -0,0 +1 @@ +uucore::bin!(uu_mcookie); diff --git a/src/uu/mcookie/src/mcookie.rs b/src/uu/mcookie/src/mcookie.rs new file mode 100644 index 0000000..ab28250 --- /dev/null +++ b/src/uu/mcookie/src/mcookie.rs @@ -0,0 +1,111 @@ +// This file is part of the uutils util-linux package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use std::{fs::File, io::Read}; + +use clap::{crate_version, Arg, ArgAction, Command}; +use md5::{Digest, Md5}; +use rand::RngCore; +use uucore::{error::UResult, format_usage, help_about, help_usage}; + +mod options { + pub const FILE: &str = "file"; + pub const MAX_SIZE: &str = "max-size"; + pub const VERBOSE: &str = "verbose"; +} + +const ABOUT: &str = help_about!("mcookie.md"); +const USAGE: &str = help_usage!("mcookie.md"); + +#[uucore::main] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { + let matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?; + + let verbose = matches.get_flag(options::VERBOSE); + + let seed_files: Vec<&str> = matches + .get_many::(options::FILE) + .unwrap_or_default() + .map(|v| v.as_str()) + .collect(); + + // TODO: Parse max size from human-readable strings (KiB, MiB, GiB etc.) + let max_size = matches + .get_one::(options::MAX_SIZE) + .map(|v| v.parse::().expect("Failed to parse max-size value")); + + let mut hasher = Md5::new(); + + for file in seed_files { + let mut f = File::open(file)?; + let mut buffer: Vec = Vec::new(); + + if let Some(max_bytes) = &max_size { + let mut handle = f.take(*max_bytes); + handle.read_to_end(&mut buffer)?; + } else { + f.read_to_end(&mut buffer)?; + } + + if verbose { + eprintln!("Got {} bytes from {}", buffer.len(), file); + } + + hasher.update(&buffer); + } + + const RANDOM_BYTES: usize = 128; + let mut rng = rand::rng(); + let mut rand_bytes = [0u8; RANDOM_BYTES]; + rng.fill_bytes(&mut rand_bytes); + + hasher.update(rand_bytes); + + if verbose { + eprintln!("Got {} bytes from randomness source", RANDOM_BYTES); + } + + let result = hasher.finalize(); + let output = result + .iter() + .map(|byte| format!("{:02x}", byte)) + .collect::>() + .join(""); + + println!("{}", output); + + Ok(()) +} + +pub fn uu_app() -> Command { + Command::new(uucore::util_name()) + .version(crate_version!()) + .about(ABOUT) + .override_usage(format_usage(USAGE)) + .infer_long_args(true) + .arg( + Arg::new(options::FILE) + .short('f') + .long("file") + .value_name("file") + .action(ArgAction::Append) + .help("use file as a cookie seed"), + ) + .arg( + Arg::new(options::MAX_SIZE) + .short('m') + .long("max-size") + .value_name("num") + .action(ArgAction::Set) + .help("limit how much is read from seed files"), + ) + .arg( + Arg::new(options::VERBOSE) + .short('v') + .long("verbose") + .action(ArgAction::SetTrue) + .help("explain what is being done"), + ) +}