日期:2011-02-15 02:11:00 来源:本站整理
让Proftpd 的数据库模块支持MD5考证[服务器安全]
本文“让Proftpd 的数据库模块支持MD5考证[服务器安全]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
这个是笔者对论坛主机的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; }
|
以下略
经以上改正后, mod_sql.c 便可以支持MD5方法的密码考证,当然,别忘了在Makefile的LIBS里增添 -lmd 指明要链接md5函数库,就一切OK
编译成功后,在 proftpd.conf 的SQLAuthTypes 指令 背面加一个 MD5,重新启动 proftpd,这家伙就认MD5考证啦.至于相关的数据库设置办法我就不多嘴了,处处都是.
评论内容只代表网友观点,与本站立场无关!
评论摘要(共 0 条,得分 0 分,平均 0 分)
查看完整评论