< 返回版块

Owen 发表于 2025-03-27 18:30

Tags:libunftp, ftp

help!

描述

hello, 大家好,我最近在使用libunftp 写一个简单的ftp服务器,通过自定义DetailUser 和 Authenticator 验证当前登录用户的用户名,密码的方式访问ftp server。 现在程序可以运行,但是我通过ftp client 访问服务时候,总是提示找不到文件或目录, 530 认证失败, 即使我输入的用户名密码是正确的。

代码片段

    let home_dir = current_login_user.home_string();
    debug!("------------------> home dir {}",&home_dir);
    let server = libunftp::Server::with_authenticator(
        Box::new(move || Filesystem::new(&home_dir)),
        Arc::new(CustomAuthenticator::new(current_login_user))a
    )
    .greeting("Welcome to the Moon ftp server^_^ ......")
    .passive_ports(port_from..port_end)
    .build()
    .unwrap();

    let _ = server.listen(format!("0.0.0.0:{}",port)).await
        .expect("Moon FTP server start failed!"); 
}




impl Authenticator<CustomUser> for CustomAuthenticator {
    /**
     * 代码解读:
     * 这里的返回值挺复杂的 Pin<Box<dyn Futrue<Result>>>
     * 最终返回一个Futrue
     * 如何返回future: https://course.rs/advance/async/async-await.html
     * ```
     * async { ... } 这样可以生成一个futrue 特征值
     * ```
     *
     * Futrue
     */
    fn authenticate<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        username: &'life1 str,
        creds: &'life2 auth::Credentials,
    ) -> Pin<
        Box<
            dyn Future<Output = Result<CustomUser, auth::AuthenticationError>>
                + Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        'life1: 'async_trait,
        'life2: 'async_trait,
        Self: 'async_trait,
    {
        Box::pin(async move {
            if username != self.user.name || creds.password.as_deref() != Some(&self.user.password) {
                error!("Authentication failed: invalid credentials");
                return Err(auth::AuthenticationError::BadUser);
            }
            Ok(self.user.clone())
        })
    }
}


错误信息

[pid 17485] openat2(11, "", {flags=O_RDONLY|O_CLOEXEC|O_PATH|O_DIRECTORY, resolve=RESOLVE_NO_MAGICLINKS|RESOLVE_BENEATH}, 24) = -1 ENOENT (没有那个文件或目录)
[2025-03-24T16:44:05Z ERROR libunftp::server::controlchan::commands::pass] No such file or directory (os error 2), source: 192.168.1.17:45242, trace-id: 0xdf3c7d28aa405ed1

试过的方法

  1. run the program by root user
  2. sudo setenforce 0
  3. chmod 755 /ftp-path/

谁能告诉我为啥呢,我已经试过很多方法了。

评论区

写评论
作者 Owen 2025-03-31 12:45

嗯嗯,我也是抱着学习的态度写的,之前没有写过返回future的程序,想着这么写试试。

👇
Bai-Jinlin: 这么写不是因为什么圣经说可以,而是那是因为这个库的Authenticator trait就是用的async_trait宏搞得,所以你用这个宏的展开写法当然行。现在要是新设计一个库就不用这么变扭的方法了。

--
👇
Owen: 按照圣经上来,圣经也说这样可以的。

--
👇
Bai-Jinlin: 第一次看见把async trait宏展开自己手写的

Bai-Jinlin 2025-03-30 10:35

这么写不是因为什么圣经说可以,而是那是因为这个库的Authenticator trait就是用的async_trait宏搞得,所以你用这个宏的展开写法当然行。现在要是新设计一个库就不用这么变扭的方法了。

--
👇
Owen: 按照圣经上来,圣经也说这样可以的。

--
👇
Bai-Jinlin: 第一次看见把async trait宏展开自己手写的

作者 Owen 2025-03-28 23:16

按照圣经上来,圣经也说这样可以的。

--
👇
Bai-Jinlin: 第一次看见把async trait宏展开自己手写的

作者 Owen 2025-03-28 23:15

是的,我把程序改造成你这样写的样子,不使用自定义的User 就可以成功登录,可以访问文件目录。 其实我自定义User主要是想把不同的用户分配不同的目录。我也是按照docs.rs中描述Authenticator样子 为自定义的User 实现了UserDetail的,为什么还是失败呢?

pub trait Authenticator<User>:
    Sync
    + Send
    + Debug
where
    User: UserDetail,

CustomUser:


#[derive(Debug, PartialEq, Eq, Clone, Default)]
struct CustomUser {
    name: String,
    password: String,
    home:String,
}

impl CustomUser {
    fn new(name: String, password: String, home: String ) -> Self {
        CustomUser { name, password, home }
    }

    fn home_string(&self) ->String{
        self.home.clone()
    }
}

impl Display for CustomUser {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "DefaultUser")
    }
}

impl UserDetail for CustomUser {

    fn home(&self) -> Option<&Path> {
        let path = Path::new(&self.home);

        if !path.exists() {
            error!("Home directory {} does not exist!", self.home);
            return None;
        }
        Some(path)
    }
}

--
👇
newcloud: 按demo写的

use unftp_sbe_fs::ServerExt;

use libunftp::auth::{DefaultUser, Authenticator, AuthenticationError, UserDetail, Credentials};

use async_trait::async_trait;
use std::sync::Arc;

#[derive(Debug)]
struct MyMyAuthenticator;

#[async_trait]
impl Authenticator<DefaultUser> for MyMyAuthenticator {
    async fn authenticate(&self, username: &str, password: &Credentials) -> Result<DefaultUser, AuthenticationError> {
        println!("username: {}", username);
        println!("password: {:?}", password);

        if let Some(pwd) = &password.password {
            if username == "hello" && pwd == "world" {
                return Ok(DefaultUser {});
            }
        }

        Err(AuthenticationError::BadPassword)
    }

    async fn cert_auth_sufficient(&self, _username: &str) -> bool {
        true
    }
}

#[tokio::main]
pub async fn main() {
    // let ftp_home = std::env::temp_dir();
    // let ftp_home = std::env::current_dir().unwrap();
    let ftp_home = std::path::PathBuf::from("/root");
    let server = libunftp::Server::with_fs(ftp_home)
    // .authenticator(Arc::new(AnonymousAuthenticator{}))
    .authenticator(Arc::new(MyMyAuthenticator{}))
        .greeting("Welcome to my FTP server")
        .passive_ports(50000..65535)
        .build()
        .unwrap();

    server.listen("127.0.0.1:2121").await;
}
Bai-Jinlin 2025-03-28 16:54

第一次看见把async trait宏展开自己手写的

newcloud 2025-03-28 15:03

按demo写的

use unftp_sbe_fs::ServerExt;

use libunftp::auth::{DefaultUser, Authenticator, AuthenticationError, UserDetail, Credentials};

use async_trait::async_trait;
use std::sync::Arc;

#[derive(Debug)]
struct MyMyAuthenticator;

#[async_trait]
impl Authenticator<DefaultUser> for MyMyAuthenticator {
    async fn authenticate(&self, username: &str, password: &Credentials) -> Result<DefaultUser, AuthenticationError> {
        println!("username: {}", username);
        println!("password: {:?}", password);

        if let Some(pwd) = &password.password {
            if username == "hello" && pwd == "world" {
                return Ok(DefaultUser {});
            }
        }

        Err(AuthenticationError::BadPassword)
    }

    async fn cert_auth_sufficient(&self, _username: &str) -> bool {
        true
    }
}

#[tokio::main]
pub async fn main() {
    // let ftp_home = std::env::temp_dir();
    // let ftp_home = std::env::current_dir().unwrap();
    let ftp_home = std::path::PathBuf::from("/root");
    let server = libunftp::Server::with_fs(ftp_home)
    // .authenticator(Arc::new(AnonymousAuthenticator{}))
    .authenticator(Arc::new(MyMyAuthenticator{}))
        .greeting("Welcome to my FTP server")
        .passive_ports(50000..65535)
        .build()
        .unwrap();

    server.listen("127.0.0.1:2121").await;
}
作者 Owen 2025-03-27 18:35

纠正一点: chmod 777 /ftp_path/

我给目录加上所有权限了,依然不能访问。

1 共 7 条评论, 1 页