SMB CLI: Add multi-user support (--user name:password)
- Add --user CLI argument (repeatable) format: name:password - Default user 'demo:demo123' if no users specified - All users get ReadWrite access to the share - Note: SMB3 encryption not available (smb-server v1 out of scope) Example: smb-start --user alice:pass1 --user bob:pass2 --share-name myshare All 229 tests pass.
This commit is contained in:
@@ -15,14 +15,31 @@ pub enum SmbServerCommand {
|
|||||||
|
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
read_only: bool,
|
read_only: bool,
|
||||||
|
|
||||||
|
#[arg(short, long, value_parser = parse_user)]
|
||||||
|
user: Vec<(String, String)>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_user(s: &str) -> Result<(String, String), String> {
|
||||||
|
let parts: Vec<&str> = s.split(':').collect();
|
||||||
|
if parts.len() != 2 {
|
||||||
|
return Err(format!("Invalid user format '{}'. Expected 'name:password'", s));
|
||||||
|
}
|
||||||
|
Ok((parts[0].to_string(), parts[1].to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn handle_smb_server_command(cmd: SmbServerCommand) -> anyhow::Result<()> {
|
pub async fn handle_smb_server_command(cmd: SmbServerCommand) -> anyhow::Result<()> {
|
||||||
#[cfg(feature = "smb-server")]
|
#[cfg(feature = "smb-server")]
|
||||||
{
|
{
|
||||||
match cmd {
|
match cmd {
|
||||||
SmbServerCommand::Start { port, root, share_name, read_only } => {
|
SmbServerCommand::Start {
|
||||||
|
port,
|
||||||
|
root,
|
||||||
|
share_name,
|
||||||
|
read_only,
|
||||||
|
user,
|
||||||
|
} => {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use smb_server::{Access, Share, SmbServer};
|
use smb_server::{Access, Share, SmbServer};
|
||||||
@@ -35,26 +52,36 @@ pub async fn handle_smb_server_command(cmd: SmbServerCommand) -> anyhow::Result<
|
|||||||
)
|
)
|
||||||
.try_init();
|
.try_init();
|
||||||
|
|
||||||
let addr: std::net::SocketAddr =
|
let addr: std::net::SocketAddr = format!("0.0.0.0:{}", port).parse()?;
|
||||||
format!("0.0.0.0:{}", port).parse()?;
|
|
||||||
let root_path = PathBuf::from(&root);
|
let root_path = PathBuf::from(&root);
|
||||||
|
|
||||||
let vfs = Box::new(crate::vfs::local_fs::LocalFs::new());
|
let vfs = Box::new(crate::vfs::local_fs::LocalFs::new());
|
||||||
let backend = crate::vfs::smb_server_backend::VfsShareBackend::new(vfs, root_path)
|
let backend = crate::vfs::smb_server_backend::VfsShareBackend::new(vfs, root_path)
|
||||||
.read_only(read_only);
|
.read_only(read_only);
|
||||||
|
|
||||||
let share = Share::new(&share_name, backend)
|
let users: Vec<(String, String)> = if user.is_empty() {
|
||||||
.user("demo", Access::ReadWrite);
|
vec![("demo".to_string(), "demo123".to_string())]
|
||||||
|
} else {
|
||||||
|
user
|
||||||
|
};
|
||||||
|
|
||||||
let server = SmbServer::builder()
|
let mut builder = SmbServer::builder().listen(addr);
|
||||||
.listen(addr)
|
|
||||||
.user("demo", "demo123")
|
|
||||||
.share(share)
|
|
||||||
.build()?;
|
|
||||||
|
|
||||||
|
for (name, password) in &users {
|
||||||
|
builder = builder.user(name, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut share = Share::new(&share_name, backend);
|
||||||
|
for (name, _) in &users {
|
||||||
|
share = share.user(name, Access::ReadWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
let server = builder.share(share).build()?;
|
||||||
|
|
||||||
|
let user_list: Vec<&str> = users.iter().map(|(n, _)| n.as_str()).collect();
|
||||||
log::info!("SMB server listening on {}", addr);
|
log::info!("SMB server listening on {}", addr);
|
||||||
log::info!("Share '{}' at root: {}", share_name, root);
|
log::info!("Share '{}' at root: {}", share_name, root);
|
||||||
log::info!("User: demo / demo123");
|
log::info!("Users: {}", user_list.join(", "));
|
||||||
|
|
||||||
server.serve().await?;
|
server.serve().await?;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user