filezilla-server批量创建用户

  有一个比较奇怪的需求,需要给 FileZilla-server 新建大量的 ftp 用户,为其配置随机密码,指定单独家目录与用户组等。

背景

  查看文档后发现 FileZilla-server 官方没有提供用户管理的 api,所有的用户配置存储在 C:\ProgramData\filezilla-server\users.xml 下(其他平台可通过管理面板的日志查看到配置路径)。

查看配置文件

我们先看看配置文件的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<filezilla xmlns:fz="https://filezilla-project.org/" xmlns="https://filezilla-project.org/" fz:product_flavour="standard" fz:product_version="1.5.1">
<default_impersonator index="0" enabled="false">
<name></name>
<password></password>
</default_impersonator>
<user name="&lt;system user>" enabled="false">
<mount_point tvfs_path="/" native_path=":h" access="1" recursive="2" />
<rate_limits inbound="unlimited" outbound="unlimited" session_inbound="unlimited" session_outbound="unlimited" />
<allowed_ips></allowed_ips>
<disallowed_ips></disallowed_ips>
<description>This user can impersonate any system user.</description>
<impersonation login_only="true" />
</user>

<user name="alliot" enabled="true">
<mount_point tvfs_path="/" native_path="D:\FTP\alliot" access="1" recursive="2" />
<rate_limits inbound="unlimited" outbound="unlimited" session_inbound="unlimited" session_outbound="unlimited" />
<allowed_ips></allowed_ips>
<disallowed_ips></disallowed_ips>
<description></description>
<group>SH</group>
<password index="1">
<hash>40yaXepMZ2hxjZUrVHYVfM15C2owZaJpL+lDOh7cqE8</hash>
<salt>5uNVtGVj9mLMAPQXzmMIHsZQrfS4mOBSv+3e6StrELg</salt>
<iterations>100000</iterations>
</password>
</user>

我们可以根据字段大致猜出:

1
2
3
用户名: alliot  
密码: 未知,加密并且加盐过
挂载点: / -> D:\FTP\alliot

  所以想要批量创建用户只需要构造这个 xml 配置文件,生成对应用户的 <user> 块即可。

密码字段怎样生成

  找遍了 官方文档和 Google 也没能找到这个密码字段是怎样加密的。
好在找到论坛一篇关于直接调用 filezilla 的 filezilla-server-crypt 命令生成密码的 hash 与 salt 值的方法:
How to import users from another FTP
课代表这里直接测试并提取了关键信息, 通过这样一条命令:

1
echo [password] | /Applications/FileZilla\ Server.app/Contents/MacOS/filezilla-server-crypt [username]

会返回类似这样的信息:

1
--username@index=1 --username.hash=dNFbyPBgME2jurr17VCv05JikQvsN/ERLpbzr+OCefM --username.salt=lmIeMEo9ZDLQY7JiGzSCgHR838u4jeGDJig+Oe2iFdc --username.iterations=100000

那么答案就显而易见了。

又不是不能用

当没法优雅的通过代码加密实现密码加密生成 hash 与 salt的时候,不如就简单粗暴的调用命令来生成吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import subprocess
import re

def password_generator(username, password) -> list:
timeout = 3

# 注意替换 filezilla-server-crypy 的路径(我这里是macOS)
cmd = f"echo {password} | /Applications/FileZilla\ Server.app/Contents/MacOS/filezilla-server-crypt {username}"
print(cmd)
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
outs, errs = proc.communicate(timeout=timeout)
if proc.returncode != 0:
print(errs)
return ["error"]
else:
return [re.findall(r".hash=(.+?) ", str(outs, encoding="utf-8"))[0],
re.findall(r".salt=(.+?) ", str(outs, encoding="utf-8"))[0]]

之后 xml 直接通过类似 jinja2 之类的模板生成即可。

为什么水一篇

  主要是当时 Google 找了一大圈也没找到对应的方式,stackoverflow 与官方论坛也看到有类似的帖子未被回答与解决,耽误了挺多时间的。于是这里大致讲一下怎么达到目的,方便遇到同样问题的同学参考。(BTW:这上古时代的东西早该淘汰了)