分享
 
 
 

让Proftpd的数据库模块支持MD5验证

王朝厨房·作者佚名  2007-01-05
窄屏简体版  字體: |||超大  

这个是笔者对论坛主机的FTP服务进行注册用户验证,论坛采用的是VBB,看了看VBB的密码加密方式,MD5,FAINT。

PROFTPD的MOD_SQL模块并不支持MD5。VBB是直接调用MYSQL的MD5()函数进行密码加密。怎么办?HACK!笔者用的PROFTPD是最新的Proftpd 1.2.8,mod_sql 版本是 4.10,查了一下 mod_sql.c 文件,发现增加一种验证方式还是很简单的,当然这个要归功mod_sql.c的程序架构设计得不错。

下面是笔者修改后得mod_sql.c的部分代码,有中文的地方是笔者加的。

#include "conf.h"

#include "privs.h"

#include "mod_sql.h"

#define _MOD_VERSION "mod_sql/4.10"

#ifdef HAVE_CRYPT_H

#include

#endif

#ifdef HAVE_LIMITS_H

#include

#endif

/**************/

/* 引入md5头文件 */

#include

/**************/

/* Uncomment the following define to allow OpenSSL hashed password checking;

* you'll also need to link with OpenSSL's crypto library ( -lcrypto )

*/

/* #define HAVE_OPENSSL */

#ifdef HAVE_OPENSSL

#include

#endif

/* default information for tables and fields */

#define MOD_SQL_DEF_USERTABLE "users"

#define MOD_SQL_DEF_USERNAMEFIELD "userid"

#define MOD_SQL_DEF_USERUIDFIELD "uid"

#define MOD_SQL_DEF_USERGIDFIELD "gid"

#define MOD_SQL_DEF_USERPASSWORDFIELD "password"

#define MOD_SQL_DEF_USERSHELLFIELD "shell"

#define MOD_SQL_DEF_USERHOMEDIRFIELD "homedir"

#define MOD_SQL_DEF_GROUPTABLE "groups"

#define MOD_SQL_DEF_GROUPNAMEFIELD "groupname"

#define MOD_SQL_DEF_GROUPGIDFIELD "gid"

#define MOD_SQL_DEF_GROUPMEMBERSFIELD "members"

/* default minimum id / default uid / default gid info.

* uids and gids less than MOD_SQL_MIN_USER_UID and

* MOD_SQL_MIN_USER_GID, respectively, get automatically

* mapped to the defaults, below. These can be

* overridden using directives

*/

#define MOD_SQL_MIN_USER_UID 999

#define MOD_SQL_MIN_USER_GID 999

#define MOD_SQL_DEF_UID 65533

#define MOD_SQL_DEF_GID 65533

#define MOD_SQL_BUFSIZE 32

/* Named Query defines */

#define SQL_SELECT_C "SELECT"

#define SQL_INSERT_C "INSERT"

#define SQL_UPDATE_C "UPDATE"

#define SQL_FREEFORM_C "FREEFORM"

/* authmask defines */

#define SQL_AUTH_USERS (1<<0)

#define SQL_AUTH_GROUPS (1<<1)

#define SQL_AUTH_USERS_DEFINITIVE (1<<2)

#define SQL_AUTH_GROUPS_DEFINITIVE (1<<3)

#define SQL_AUTH_USERSET (1<<4)

#define SQL_AUTH_GROUPSET (1<<5)

#define SQL_FAST_USERSET (1<<6)

#define SQL_FAST_GROUPSET (1<<7)

#define SQL_GROUPS (cmap.authmask & SQL_AUTH_GROUPS)

#define SQL_USERS (cmap.authmask & SQL_AUTH_USERS)

#define SQL_GROUPSET (cmap.authmask & SQL_AUTH_GROUPSET)

#define SQL_USERSET (cmap.authmask & SQL_AUTH_USERSET)

#define SQL_FASTGROUPS (cmap.authmask & SQL_FAST_GROUPSET)

#define SQL_FASTUSERS (cmap.authmask & SQL_FAST_USERSET)

#define SQL_GROUPGOD (cmap.authmask & SQL_AUTH_GROUPS_DEFINITIVE)

#define SQL_USERGOD (cmap.authmask & SQL_AUTH_USERS_DEFINITIVE)

/*

* externs, function signatures.. whatever necessary to make

* the compiler happy..

*/

extern pr_response_t *resp_list,*resp_err_list;

static char *_sql_where(pool *p, int cnt, ...);

MODRET cmd_getgrent(cmd_rec *);

MODRET cmd_setgrent(cmd_rec *);

pool *sql_pool;

/*

* cache typedefs

*/

#define CACHE_SIZE 13

typedef struct cache_entry {

struct cache_entry *list_next;

struct cache_entry *bucket_next;

void *data;

} cache_entry_t;

/* this struct holds invariant information for the current session */

static struct

{

/*

* info valid after getpwnam

*/

char *authuser; /* current authorized user */

struct passwd *authpasswd; /* and their passwd struct */

/*

* generic status information

*/

int status; /* is mod_sql on? */

int authmask; /* authentication mask.

* see set_sqlauthenticate for info */

/*

* user table and field information

*/

char *usrtable; /* user info table name */

char *usrfield; /* user name field */

char *pwdfield; /* user password field */

char *uidfield; /* user uid field */

char *gidfield; /* user gid field */

char *homedirfield; /* user homedir field */

char *shellfield; /* user login shell field */

char *userwhere; /* users where clause */

/*

* group table and field information

*/

char *grptable; /* group info table name */

char *grpfield; /* group name field */

char *grpgidfield; /* group gid field */

char *grpmembersfield; /* group members field */

char *groupwhere; /* groups where clause */

/*

* other information

*/

array_header *authlist; /* auth handler list */

char *defaulthomedir; /* default homedir if no field specified */

int buildhomedir; /* create homedir if it doesn't exist? */

uid_t minid; /* users UID must be this or greater */

uid_t minuseruid; /* users UID must be this or greater */

gid_t minusergid; /* users UID must be this or greater */

uid_t defaultuid; /* default UID if none in database */

gid_t defaultgid; /* default GID if none in database */

cache_entry_t *curr_group; /* next group in group array for getgrent */

cache_entry_t *curr_passwd; /* next passwd in passwd array for getpwent */

int group_cache_filled;

int passwd_cache_filled;

unsigned char negative_cache; /* cache negative as well as positive lookups */

/*

* mod_ratio data -- someday this needs to be removed from mod_sql

*/

char *sql_fstor; /* fstor int(11) NOT NULL DEFAULT '0', */

char *sql_fretr; /* fretr int(11) NOT NULL DEFAULT '0', */

char *sql_bstor; /* bstor int(11) NOT NULL DEFAULT '0', */

char *sql_bretr; /* bretr int(11) NOT NULL DEFAULT '0', */

char *sql_frate; /* frate int(11) NOT NULL DEFAULT '5', */

char *sql_fcred; /* fcred int(2) NOT NULL DEFAULT '15', */

char *sql_brate; /* brate int(11) NOT NULL DEFAULT '5', */

char *sql_bcred; /* bcred int(2) NOT NULL DEFAULT '150000', */

/*

* precomputed strings

*/

char *usrfields;

char *grpfields;

}

cmap;

/*

* cache functions

*/

typedef unsigned int ( * val_func ) ( const void * );

typedef int ( * cmp_func ) ( const void *, const void * );

typedef struct {

/* memory pool for this object */

pool *pool;

/* cache buckets */

cache_entry_t *buckets[ CACHE_SIZE ];

/* cache functions */

val_func hash_val;

cmp_func cmp;

/* list pointers */

cache_entry_t *head;

/* list size */

unsigned int nelts;

} cache_t;

cache_t *group_name_cache;

cache_t *group_gid_cache;

cache_t *passwd_name_cache;

cache_t *passwd_uid_cache;

static cache_t *make_cache( pool *p, val_func hash_val, cmp_func cmp )

{

cache_t *res;

if ( ( p == NULL ) || ( hash_val == NULL ) ||

( cmp == NULL ) )

return NULL;

res = ( cache_t * ) pcalloc( p, sizeof( cache_t ) );

res->pool = p;

res->hash_val = hash_val;

res->cmp = cmp;

res->head = NULL;

res->nelts = 0;

return res;

}

static cache_entry_t *cache_addentry( cache_t *cache, void *data )

{

cache_entry_t *entry;

int hashval;

if ( ( cache == NULL ) || ( data == NULL ) )

return NULL;

/* create the entry */

entry = ( cache_entry_t * ) pcalloc( cache->pool,

sizeof( cache_entry_t ) );

entry->data = data;

/* deal with the list */

if ( cache->head == NULL ) {

cache->head = entry;

} else {

entry->list_next = cache->head;

cache->head = entry;

}

/* deal with the buckets */

hashval = cache->hash_val( data ) % CACHE_SIZE;

if ( cache->buckets[ hashval ] == NULL ) {

cache->buckets[ hashval ] = entry;

} else {

entry->bucket_next = cache->buckets[ hashval ];

cache->buckets[ hashval ] = entry;

}

cache->nelts++;

return entry;

}

static void *cache_findvalue( cache_t *cache, void *data )

{

cache_entry_t *entry;

int hashval;

if ( ( cache == NULL ) || ( data == NULL ) ) return NULL;

hashval = cache->hash_val( data ) % CACHE_SIZE;

entry = cache->buckets[ hashval ];

while ( entry != NULL ) {

if ( cache->cmp( data, entry->data ) )

break;

else

entry = entry->bucket_next;

}

return ( ( entry == NULL ) ? NULL : entry->data );

}

cmd_rec *_sql_make_cmd(pool * cp, int argc, ...)

{

pool *newpool = NULL;

cmd_rec *c = NULL;

va_list args;

int i = 0;

newpool = make_sub_pool( cp );

c = pcalloc(newpool, sizeof(cmd_rec));

c->argc = argc;

c->stash_index = -1;

c->pool = newpool;

c->argv = pcalloc(newpool, sizeof(void *) * (argc));

c->tmp_pool = newpool;

va_start(args, argc);

for (i = 0; i < argc; i++)

c->argv[i] = (void *) va_arg(args, char *);

va_end(args);

return c;

}

void _sql_free_cmd( cmd_rec *cmd )

{

destroy_pool( cmd->pool );

return;

}

static void _sql_check_cmd(cmd_rec *cmd, char *msg)

{

if ((!cmd) || (!cmd->tmp_pool)) {

log_pri(PR_LOG_ERR, _MOD_VERSION ": '%s' was passed an invalid cmd_rec. "

"Shutting down.", msg);

sql_log(DEBUG_WARN, "'%s' was passed an invalid cmd_rec. Shutting down.",

msg);

end_login(1);

}

return;

}

static modret_t *_sql_check_response(modret_t * mr)

{

if (!MODRET_ISERROR(mr))

return mr;

sql_log(DEBUG_WARN, "%s", "unrecoverable backend error");

sql_log(DEBUG_WARN, "error: '%s'", mr->mr_numeric);

sql_log(DEBUG_WARN, "message: '%s'", mr->mr_message);

end_login(1);

/* make the compiler happy */

return NULL;

}

static modret_t * _sql_dispatch(cmd_rec *cmd, char *cmdname)

{

modret_t *mr = NULL;

int i = 0;

for(i = 0; sql_cmdtable[i].command; i++)

if(!strcmp(cmdname,sql_cmdtable[i].command)) {

pr_signals_block();

mr = sql_cmdtable[i].handler(cmd);

pr_signals_unblock();

return mr;

}

sql_log(DEBUG_WARN, "unknown backend handler '%s'", cmdname );

return ERROR(cmd);

}

static char *_sql_strip_spaces( pool *p, char *str )

{

char *start = NULL, *finish = NULL;

if (!str) return NULL;

/* first, find the non-whitespace start of the given string */

for (start = str; isspace((int) *start); start++);

/* now, find the non-whitespace end of the given string */

for (finish = &str[strlen(str)-1]; isspace((int) *finish); finish--);

*++finish = ';

/* the space-stripped string is, then, everything from start to finish */

return pstrdup( p, start );

}

/*****************************************************************

*

* AUTHENTICATION FUNCTIONS

*

*****************************************************************/

static modret_t *check_auth_crypt(cmd_rec * cmd, const char *c_clear,

const char *c_hash)

{

int success = 0;

if (*c_hash == ') return ERROR_INT(cmd, PR_AUTH_BADPWD);

success = !strcmp((char *) crypt(c_clear, c_hash), c_hash);

return success ? HANDLED(cmd) : ERROR_INT(cmd, PR_AUTH_BADPWD);

}

static modret_t *check_auth_plaintext(cmd_rec * cmd, const char *c_clear,

const char *c_hash)

{

int success = 0;

if (*c_hash == ' ) return ERROR_INT(cmd, PR_AUTH_BADPWD);

success = !strcmp(c_clear, c_hash);

return success ? HANDLED(cmd) : ERROR_INT(cmd, PR_AUTH_BADPWD);

}

static modret_t *check_auth_empty(cmd_rec * cmd, const char *c_clear,

const char *c_hash)

{

int success = 0;

success = !strcmp(c_hash, "");

return success ? HANDLED(cmd) : ERROR_INT(cmd, PR_AUTH_BADPWD);

}

static modret_t *check_auth_backend(cmd_rec * cmd, const char *c_clear,

const char *c_hash)

{

modret_t * mr = NULL;

if (*c_hash == ' ) return ERROR_INT(cmd, PR_AUTH_BADPWD);

mr = _sql_dispatch( _sql_make_cmd(cmd->tmp_pool, 3, "default",

c_clear, c_hash),

"sql_checkauth" );

return mr;

}

/******************************************************/

/* 增加 MD5 验证函数*, 简单之至, 照猫画虎*/

static modret_t *check_auth_md5(cmd_rec * cmd, const char *c_clear, const char *c_hash)

{

int success = 0;

size_t len = strlen(c_clear);

char buf[33];

/* specifically disallow empty passwords */

if (*c_hash == ' ) return ERROR_INT(cmd, PR_AUTH_BADPWD);

MD5Data(c_clear, len, buf); /* 调用MD5函数 */

success = !strcmp(buf, c_hash);

return success ? HANDLED(cmd) : ERROR_INT(cmd, PR_AUTH_BADPWD);

}

/****************************************************/

#ifdef HAVE_OPENSSL

static modret_t *check_auth_openssl(cmd_rec * cmd, const char *c_clear,

const char *c_hash)

{

/*

* c_clear : plaintext password provided by user

* c_hash : combination digest name and hashed

* value, of the form {digest}hash

*/

EVP_MD_CTX mdctx;

EVP_ENCODE_CTX EVP_Encode;

const EVP_MD *md;

unsigned char md_value[EVP_MAX_MD_SIZE];

int md_len, returnValue;

char buff[EVP_MAX_KEY_LENGTH];

char *digestname; /* ptr to name of the digest function */

char *hashvalue; /* ptr to hashed value we're comparing to */

char *copyhash; /* temporary copy of the c_hash string */

if (c_hash[0] != '{') {

return ERROR_INT(cmd, PR_AUTH_BADPWD);

}

/*

* we need a copy of c_hash

*/

copyhash = pstrdup(cmd->tmp_pool, c_hash);

digestname = copyhash + 1;

hashvalue = (char *) strchr(copyhash, '}');

if (hashvalue == NULL) {

return ERROR_INT(cmd, PR_AUTH_BADPWD);

}

*hashvalue = ';

hashvalue++;

OpenSSL_add_all_digests();

md = EVP_get_digestbyname(digestname);

if (!md) {

return ERROR_INT(cmd, PR_AUTH_BADPWD);

}

EVP_DigestInit(&mdctx, md);

EVP_DigestUpdate(&mdctx, c_clear, strlen(c_clear));

EVP_DigestFinal(&mdctx, md_value, &md_len);

EVP_EncodeInit(&EVP_Encode);

EVP_EncodeBlock(buff, md_value, md_len);

returnValue = strcmp(buff, hashvalue);

return returnValue ? ERROR_INT(cmd, PR_AUTH_BADPWD) : HANDLED(cmd);

}

#endif

/*

* support for general-purpose authentication schemes

*/

#define PLAINTEXT_AUTH_FLAG 1<<0

#define CRYPT_AUTH_FLAG 1<<1

#define BACKEND_AUTH_FLAG 1<<2

#define EMPTY_AUTH_FLAG 1<<3

/* 插入MD5验证模式,把OPENSSL往后推,OPENSSL本来是 1<<4 */

#define MD5_AUTH_FLAG 1<<4

/***************/

#ifdef HAVE_OPENSSL

#define OPENSSL_AUTH_FLAG 1<<5

#endif

typedef modret_t *(*auth_func_ptr) (cmd_rec *, const char *, const char *);

typedef struct

{

char *name;

auth_func_ptr check_function;

int flag;

}

auth_type_entry;

static auth_type_entry supported_auth_types[] = {

{"Plaintext", check_auth_plaintext, PLAINTEXT_AUTH_FLAG},

{"Crypt", check_auth_crypt, CRYPT_AUTH_FLAG},

{"Backend", check_auth_backend, BACKEND_AUTH_FLAG},

{"Empty", check_auth_empty, EMPTY_AUTH_FLAG},

{"MD5", check_auth_md5, MD5_AUTH_FLAG}, /* 这里往验证类型条目结构里增加MD5验证 */

#ifdef HAVE_OPENSSL

{"OpenSSL", check_auth_openssl, OPENSSL_AUTH_FLAG},

#endif

/*

* add additional encryption types below

*/

{NULL, NULL, 0}

};

static auth_type_entry *get_auth_entry(char *name)

{

auth_type_entry *ate = supported_auth_types;

while (ate->name) {

if (!strcasecmp(ate->name, name)) {

return ate;

}

ate++;

}

return NULL;

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有