SMB CLI: Add multi-user support (--user name:password)
Some checks failed
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled

- 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:
Warren
2026-06-20 20:44:23 +08:00
parent 51ca0c4633
commit d1467f03bd

View File

@@ -15,14 +15,31 @@ pub enum SmbServerCommand {
#[arg(long)]
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<()> {
#[cfg(feature = "smb-server")]
{
match cmd {
SmbServerCommand::Start { port, root, share_name, read_only } => {
SmbServerCommand::Start {
port,
root,
share_name,
read_only,
user,
} => {
use std::path::PathBuf;
use smb_server::{Access, Share, SmbServer};
@@ -35,26 +52,36 @@ pub async fn handle_smb_server_command(cmd: SmbServerCommand) -> anyhow::Result<
)
.try_init();
let addr: std::net::SocketAddr =
format!("0.0.0.0:{}", port).parse()?;
let addr: std::net::SocketAddr = format!("0.0.0.0:{}", port).parse()?;
let root_path = PathBuf::from(&root);
let vfs = Box::new(crate::vfs::local_fs::LocalFs::new());
let backend = crate::vfs::smb_server_backend::VfsShareBackend::new(vfs, root_path)
.read_only(read_only);
let share = Share::new(&share_name, backend)
.user("demo", Access::ReadWrite);
let users: Vec<(String, String)> = if user.is_empty() {
vec![("demo".to_string(), "demo123".to_string())]
} else {
user
};
let server = SmbServer::builder()
.listen(addr)
.user("demo", "demo123")
.share(share)
.build()?;
let mut builder = SmbServer::builder().listen(addr);
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!("Share '{}' at root: {}", share_name, root);
log::info!("User: demo / demo123");
log::info!("Users: {}", user_list.join(", "));
server.serve().await?;
}