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)]
|
||||
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?;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user