为 Serv-U 编写插件
需要对服务器上的 ftp server 作扩展,ftp server 采用的是 Serv-U
6.0。看了一些插件,有免费的,有商业的,都无法达到我们需求的功能,于是决定自己为 Serv-U 编写插件。查看帮助文件中的 Extending Serv-U
部分,大概了解了 Serv-U 插件的基本情况。
由于我们只需要控制存取信息所以我们只关注和介绍一下 Access Verification DLLs 部分,还有 Event Notification
DLLs 基本和前者相似。现有的多数插件都是 Access Verificatin DLLs,这部分的内容比较多些,比如
用户登陆,密码更改,执行权限,配额,等等,一些 ftp 与论坛挂接的插件都是基于这部分写的。这个 DLL 必须导出一个函数:
extern “C”
int
__declspec(
dllexport )
cdecl
HandleClientEvent(RClientEventStr*
pEventStruc);
插件的工作原理就是,Serv-U 服务器根据初始化文件的内容装载插件 DLL, 然后用 GetProcessAddress()
获得这个导出函数的地址,当有事件发生时,服务器就会调用这个函数并将相关信息通过参数 RClientEventStr*
pEventStruc 传递给我们,RClientEventStr
结构定义如下:
// event structure
for communications with external DLL’s
struct
RClientEventStr
{
int
Event; // event
code
int
Flag; // flag,
meaning depends on event
//char
User[151];//this member upgraded to 151 since v6.0 // user name
char
User[40];
// it is 40 byte
before 5.0
char
Aux[512]; // auxiliary area,
usage depends on event
char
HostIP[16]; // IP number of
host that client is connected to
unsigned
long
SessionID; // client session
ID
int
DomainID; // unique ID for
the domain the client connected to
int
DomainPort; // server port
number the client connected to
};
这里有一点需要注意的是 User 成员在 6.0 以前是 40 个元素,从 6.0 开始变成 150 个元素,最近又因为修整一个Null
Terminater 符号越界的 bug 又被定义成了 151 个元素,所以大家需要关注一下插件将在哪个版本的 Serv-U
上工作,否则我们的程序就会发生错误,甚至会使 Serv-U 崩溃。
Event 成员是事件 ID, 相关定义如下:
// event
definitions, for usage by external DLL’s
#define SRVU_LoginMesFile 1
// get login
message file
#define SRVU_HomeDir 2
// get home
dir
#define SRVU_Password 3
// verify
password
#define SRVU_IPAccess 4
// verify IP
access
#define SRVU_WriteFile 5
// verify write
access
#define SRVU_ReadFile 6
// verify read
access
#define SRVU_ModifyFile 7
// verify mod./del.
file access
#define SRVU_ExecProg 8
// verify execute
access
#define SRVU_ListDir 9
// verify dir
listing access
#define SRVU_ChangeDir 10
// verify dir
change access
#define SRVU_DeleteDir 11
// verify dir
delete access
#define SRVU_CreateDir 12
// verify dir
create access
#define SRVU_HideHidden 13
// get setting for
‘hide hidden files’
#define SRVU_RelPaths 14
// get setting for
‘relative paths’
#define SRVU_RatioType 15
// get setting for
type of ratios
#define SRVU_RatioDown 16
// get setting for
download ratio
#define SRVU_RatioUp
17 // get setting for
upload ratio
#define SRVU_RatioCredit 18
// get/adjust ratio
credit setting
#define SRVU_RatioFree 19
// verify if file
is free for ratios
#define SRVU_QuotaEnable 20
// verify if disk
quota is enabled
#define SRVU_QuotaChange 21
// change in disk
quota
#define SRVU_QuotaMax 22
// maximum disk
quota
#define SRVU_AlwaysLogin 23
// always allow
login
#define SRVU_OneLoginPerIP 24
// allow one login
per user/IP pair
#define SRVU_LogClientIP 25
// log client from
this IP address
#define SRVU_SpeedLimit 26
// maximum transfer
speed
#define SRVU_PassChange 27
// change user’s
password
#define SRVU_TimeOut 28
// get user
time-out value
#define SRVU_MaxUsers
29 // max. no. of
users for account
#define SRVU_PassChallenge 30
// get password
challenge if needed
#define SRVU_Connect 31
// information
only: client connected
#define SRVU_Close 32
// information
only: client disconnected
#define SRVU_MaxLoginPerIP 33
// max. no. of
logins from same IP for user
#define SRVU_VerifyPasswd 34
// verify old
password before changing it
#define SRVU_AppendFile 35
// verify append
file access
#define SRVU_SignOnMes 36
// get signon
message file
#define SRVU_SignOffMes 37
// get signoff
message file
#define SRVU_Maintenance 38
// switch to
maintenance mode
#define SRVU_SessionTimeOut 39 // session
time-out
#define SRVU_SecureOnly 40
// only allow login
over secure connection
#define SRVU_PassExpired 41
// verify if
password is expired
这里是最新版本所包含的 41 个事件, 较早的版本没有这么多事件,这里也请大家注意查阅相关版本的资料。
所有的扩展功能就看这个导出函数 HandleClientEvent 了,我们只需要在里面实现一个
switch…case..多路分枝语句就可以根据需要处理事件了。
举个例子说明一下大致的编写方法,如果我们需要让论坛或其他系统用户用他们在论坛或其他系统里的帐户密码登陆 ftp 我们可以处理 SRVU_Password 事件:
int
__declspec(
dllexport )
cdecl
HandleClientEvent(RClientEventStr*
pEventStruc)
//
******
// Event
handler.
//
******
{
int
Ret=0; //
default return value -> not handling event
switch
(pEventStruc->Event)
{
case
SRVU_Password:
if(
CheckForumUser(pEventStruc->User,
pEventStruc->Aux)
)
{
pEventStruc->Flag =
1;
}
Ret = 1;
// Don’t forget
return 1 to Serv-U
break;
}
return(Ret);
}
当我们确认用户有效以后就将 Flag 置 1 (true),同时也要 return Ret=1;
Aux 是综合数据成员,不同事件时存储不同的信息,在这个事件中 Aux 中是用户的密码!
巧妙的处理这些事件便可以随心所欲的扩展我们的 Serv-U 了。
使 Serv-U 加载我们的插件的方法是在 ServUDaemon.ini 的 [EXTERNAL]
片段加入如下变量
ClientCheckDLL1=MyAddon1.dll
ClientCheckDLL2=MyAddon2.dll
以此类推。

