From 324376a941201fe0071a094f9078a68af1f44ee6 Mon Sep 17 00:00:00 2001 From: Aston Turing Date: Wed, 29 Nov 2023 21:15:36 +0800 Subject: [PATCH] Add owner and permssions for UnixListener --- Cargo.toml | 10 ++++++-- crates/core/Cargo.toml | 3 +++ crates/core/src/conn/unix.rs | 49 ++++++++++++++++++++++++++++++++---- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 89e61b76a..21420cda9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,12 @@ documentation = "https://docs.rs/salvo/" readme = "./README.md" keywords = ["http", "async", "web", "framework", "server"] license = "MIT OR Apache-2.0" -categories = ["web-programming::http-server", "web-programming::websocket", "network-programming", "asynchronous"] +categories = [ + "web-programming::http-server", + "web-programming::websocket", + "network-programming", + "asynchronous", +] [workspace.dependencies] aead = "0.5" @@ -58,6 +63,7 @@ moka = "0.12" multer = "2" multimap = "0.9" native-tls = "0.2" +nix = { version = "0.27", default-features = false } once_cell = "1" openssl = "0.10" opentelemetry-http = { version = "0.10", default-features = false } @@ -76,7 +82,7 @@ quote = "1" rand = "0.8" rcgen = "0.11" regex = "1" -reqwest = {version = "0.11", default-features = false } +reqwest = { version = "0.11", default-features = false } ring = "0.17" rust_decimal = "1" rustls = "0.21" diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index dda6eb341..2d6288507 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -90,5 +90,8 @@ brotli = { workspace = true, optional = true, features = ["default"] } flate2 = { workspace = true, optional = true, features = ["default"] } zstd = { workspace = true, optional = true, features = ["default"] } +[target.'cfg(unix)'.dependencies] +nix = { workspace = true, features = ["fs", "user"] } + [dev-dependencies] fastrand = { workspace = true } diff --git a/crates/core/src/conn/unix.rs b/crates/core/src/conn/unix.rs index b22318e57..ccd9e52b1 100644 --- a/crates/core/src/conn/unix.rs +++ b/crates/core/src/conn/unix.rs @@ -1,4 +1,5 @@ //! UnixListener module +use std::fs::{set_permissions, Permissions}; use std::io::{Error as IoError, ErrorKind, Result as IoResult}; use std::path::Path; use std::sync::Arc; @@ -6,7 +7,8 @@ use std::time::Duration; use http::uri::Scheme; use tokio::net::{UnixListener as TokioUnixListener, UnixStream}; -use tokio_util::sync::CancellationToken; +use tokio_util::sync::CancellationToken; +use nix::unistd::{Gid, chown, Uid}; use crate::async_trait; use crate::conn::{Holding, HttpBuilder}; @@ -18,26 +20,63 @@ use super::{Accepted, Acceptor, Listener}; /// `UnixListener` is used to create a Unix socket connection listener. #[cfg(unix)] pub struct UnixListener { - path: T, + path: T, + permissions: Option, + owner: Option<(Option, Option)>, } #[cfg(unix)] impl UnixListener { /// Creates a new `UnixListener` bind to the specified path. #[inline] pub fn new(path: T) -> UnixListener { - UnixListener { path } + UnixListener { path, + permissions: None, + owner: None, } + } + + /// Provides permissions to be set on actual bind. + #[inline] + pub fn permissions(mut self, permissions: impl Into>) -> Self { + self.permissions = permissions.into(); + self + } + + #[inline] + /// Provides owner to be set on actual bind. + pub fn owner(mut self, uid: Option, gid: Option) -> Self { + self.owner = Some((uid.map(|v| Uid::from_raw(v)), gid.map(|v| Gid::from_raw(v)))); + self } } #[async_trait] impl Listener for UnixListener where - T: AsRef + Send, + T: AsRef + Send + Clone, { type Acceptor = UnixAcceptor; async fn try_bind(self) -> IoResult { - let inner = TokioUnixListener::bind(self.path)?; + let inner = match (self.permissions, self.owner) { + (Some(permissions), Some((uid, gid))) => { + let inner = TokioUnixListener::bind(self.path.clone())?; + set_permissions(self.path.clone(), permissions)?; + chown(self.path.as_ref().as_os_str().into(), uid, gid)?; + inner + } + (Some(permissions), None) => { + let inner = TokioUnixListener::bind(self.path.clone())?; + set_permissions(self.path.clone(), permissions)?; + inner + } + (None, Some((uid, gid))) => { + let inner = TokioUnixListener::bind(self.path.clone())?; + chown(self.path.as_ref().as_os_str().into(), uid, gid)?; + inner + } + (None, None) => TokioUnixListener::bind(self.path)?, + }; + let holding = Holding { local_addr: inner.local_addr()?.into(), http_versions: vec![Version::HTTP_11],