[mod_auth] http_auth_info_t digest abstraction
This commit is contained in:
parent
07fef25867
commit
60f4cf3ad8
|
@ -137,6 +137,19 @@ void http_auth_setenv(connection *con, const char *username, size_t ulen, const
|
|||
http_header_env_set(con, CONST_STR_LEN("AUTH_TYPE"), auth_type, alen);
|
||||
}
|
||||
|
||||
unsigned int http_auth_digest_len (int algo)
|
||||
{
|
||||
if (algo & (HTTP_AUTH_DIGEST_SHA256 | HTTP_AUTH_DIGEST_SHA512_256)) {
|
||||
/* HTTP_AUTH_DIGEST_SHA512_256_BINLEN */
|
||||
return HTTP_AUTH_DIGEST_SHA256_BINLEN;
|
||||
}
|
||||
if (algo & HTTP_AUTH_DIGEST_MD5) {
|
||||
return HTTP_AUTH_DIGEST_MD5_BINLEN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int http_auth_digest_hex2bin (const char *hexstr, size_t len, unsigned char *bin, size_t binlen)
|
||||
{
|
||||
/* validate and transform 32-byte MD5 hex string to 16-byte binary MD5,
|
||||
|
|
|
@ -8,6 +8,20 @@
|
|||
|
||||
void http_auth_dumbdata_reset (void);
|
||||
|
||||
typedef enum http_auth_digest_type {
|
||||
HTTP_AUTH_DIGEST_NONE = 0
|
||||
,HTTP_AUTH_DIGEST_SESS = 0x01
|
||||
,HTTP_AUTH_DIGEST_MD5 = 0x02
|
||||
,HTTP_AUTH_DIGEST_SHA256 = 0x04
|
||||
,HTTP_AUTH_DIGEST_SHA512_256 = 0x08
|
||||
} http_auth_digest_type;
|
||||
|
||||
#define HTTP_AUTH_DIGEST_MD5_BINLEN 16 /* MD5_DIGEST_LENGTH */
|
||||
#define HTTP_AUTH_DIGEST_SHA256_BINLEN 32 /* SHA256_DIGEST_LENGTH */
|
||||
#define HTTP_AUTH_DIGEST_SHA512_256_BINLEN 32 /* SHA512_256_DIGEST_LENGTH */
|
||||
|
||||
unsigned int http_auth_digest_len (int algo);
|
||||
|
||||
struct http_auth_scheme_t;
|
||||
struct http_auth_require_t;
|
||||
struct http_auth_backend_t;
|
||||
|
@ -16,6 +30,7 @@ typedef struct http_auth_require_t {
|
|||
const struct http_auth_scheme_t *scheme;
|
||||
buffer *realm;
|
||||
int valid_user;
|
||||
int algorithm;
|
||||
array *user;
|
||||
array *group;
|
||||
array *host;
|
||||
|
@ -25,10 +40,21 @@ http_auth_require_t * http_auth_require_init (void);
|
|||
void http_auth_require_free (http_auth_require_t *require);
|
||||
int http_auth_match_rules (const http_auth_require_t *require, const char *user, const char *group, const char *host);
|
||||
|
||||
typedef struct http_auth_info_t {
|
||||
int dalgo;
|
||||
unsigned int dlen;
|
||||
const char *username;
|
||||
size_t ulen;
|
||||
const char *realm;
|
||||
size_t rlen;
|
||||
/*(must be >= largest binary digest length accepted above)*/
|
||||
unsigned char digest[32];
|
||||
} http_auth_info_t;
|
||||
|
||||
typedef struct http_auth_backend_t {
|
||||
const char *name;
|
||||
handler_t(*basic)(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
|
||||
handler_t(*digest)(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]);
|
||||
handler_t(*digest)(server *srv, connection *con, void *p_d, http_auth_info_t *ai);
|
||||
void *p_d;
|
||||
} http_auth_backend_t;
|
||||
|
||||
|
|
|
@ -560,6 +560,7 @@ static handler_t mod_auth_check_digest(server *srv, connection *con, void *p_d,
|
|||
const char *m = NULL;
|
||||
int i;
|
||||
buffer *b;
|
||||
http_auth_info_t ai;
|
||||
|
||||
li_MD5_CTX Md5Ctx;
|
||||
HASH HA1;
|
||||
|
@ -670,7 +671,14 @@ static handler_t mod_auth_check_digest(server *srv, connection *con, void *p_d,
|
|||
return mod_auth_send_400_bad_request(srv, con);
|
||||
}
|
||||
|
||||
if (!buffer_is_equal_string(require->realm, realm, strlen(realm))) {
|
||||
ai.dalgo = HTTP_AUTH_DIGEST_MD5;
|
||||
ai.dlen = HTTP_AUTH_DIGEST_MD5_BINLEN;
|
||||
ai.username = username;
|
||||
ai.ulen = strlen(username);
|
||||
ai.realm = realm;
|
||||
ai.rlen = strlen(realm);
|
||||
|
||||
if (!buffer_is_equal_string(require->realm, ai.realm, ai.rlen)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"digest: realm mismatch");
|
||||
buffer_free(b);
|
||||
|
@ -721,8 +729,7 @@ static handler_t mod_auth_check_digest(server *srv, connection *con, void *p_d,
|
|||
}
|
||||
}
|
||||
|
||||
/* password-string == HA1 */
|
||||
switch (backend->digest(srv, con, backend->p_d, username, realm, HA1)) {
|
||||
switch (backend->digest(srv, con, backend->p_d, &ai)) {
|
||||
case HANDLER_GO_ON:
|
||||
break;
|
||||
case HANDLER_WAIT_FOR_EVENT:
|
||||
|
@ -736,6 +743,7 @@ static handler_t mod_auth_check_digest(server *srv, connection *con, void *p_d,
|
|||
buffer_free(b);
|
||||
return mod_auth_send_401_unauthorized_digest(srv, con, require->realm, 0);
|
||||
}
|
||||
memcpy(HA1, ai.digest, ai.dlen);
|
||||
|
||||
if (algorithm &&
|
||||
strcasecmp(algorithm, "md5-sess") == 0) {
|
||||
|
@ -823,7 +831,7 @@ static handler_t mod_auth_check_digest(server *srv, connection *con, void *p_d,
|
|||
} /*(future: might send nextnonce when expiration is imminent)*/
|
||||
}
|
||||
|
||||
http_auth_setenv(con, username, strlen(username), CONST_STR_LEN("Digest"));
|
||||
http_auth_setenv(con, ai.username, ai.ulen, CONST_STR_LEN("Digest"));
|
||||
|
||||
buffer_free(b);
|
||||
|
||||
|
|
|
@ -59,9 +59,9 @@ typedef struct {
|
|||
plugin_config conf;
|
||||
} plugin_data;
|
||||
|
||||
static handler_t mod_authn_file_htdigest_digest(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]);
|
||||
static handler_t mod_authn_file_htdigest_digest(server *srv, connection *con, void *p_d, http_auth_info_t *ai);
|
||||
static handler_t mod_authn_file_htdigest_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
|
||||
static handler_t mod_authn_file_plain_digest(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]);
|
||||
static handler_t mod_authn_file_plain_digest(server *srv, connection *con, void *p_d, http_auth_info_t *ai);
|
||||
static handler_t mod_authn_file_plain_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
|
||||
static handler_t mod_authn_file_htpasswd_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
|
||||
|
||||
|
@ -197,20 +197,9 @@ static int mod_authn_file_patch_connection(server *srv, connection *con, plugin_
|
|||
#undef PATCH
|
||||
|
||||
|
||||
static int mod_authn_file_htdigest_get(server *srv, const buffer *auth_fn, const buffer *username, const buffer *realm, unsigned char HA1[16]) {
|
||||
FILE *fp;
|
||||
static int mod_authn_file_htdigest_get_loop(server *srv, FILE *fp, const buffer *auth_fn, http_auth_info_t *ai) {
|
||||
char f_user[1024];
|
||||
|
||||
if (buffer_string_is_empty(auth_fn)) return -1;
|
||||
if (buffer_is_empty(username) || buffer_is_empty(realm)) return -1;
|
||||
|
||||
fp = fopen(auth_fn->ptr, "r");
|
||||
if (NULL == fp) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", auth_fn, "failed:", strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (NULL != fgets(f_user, sizeof(f_user), fp)) {
|
||||
char *f_pwd, *f_realm;
|
||||
size_t u_len, r_len;
|
||||
|
@ -246,47 +235,63 @@ static int mod_authn_file_htdigest_get(server *srv, const buffer *auth_fn, const
|
|||
r_len = f_pwd - f_realm;
|
||||
f_pwd++;
|
||||
|
||||
if (buffer_string_length(username) == u_len &&
|
||||
(buffer_string_length(realm) == r_len) &&
|
||||
(0 == strncmp(username->ptr, f_user, u_len)) &&
|
||||
(0 == strncmp(realm->ptr, f_realm, r_len))) {
|
||||
if (ai->ulen == u_len && ai->rlen == r_len
|
||||
&& 0 == memcmp(ai->username, f_user, u_len)
|
||||
&& 0 == memcmp(ai->realm, f_realm, r_len)) {
|
||||
/* found */
|
||||
|
||||
size_t pwd_len = strlen(f_pwd);
|
||||
if (f_pwd[pwd_len-1] == '\n') --pwd_len;
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (pwd_len != (ai->dlen << 1)) continue;
|
||||
return http_auth_digest_hex2bin(f_pwd, pwd_len,
|
||||
HA1, sizeof(HA1));
|
||||
ai->digest, sizeof(ai->digest));
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static handler_t mod_authn_file_htdigest_digest(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]) {
|
||||
static int mod_authn_file_htdigest_get(server *srv, connection *con, void *p_d, http_auth_info_t *ai) {
|
||||
plugin_data *p = (plugin_data *)p_d;
|
||||
buffer *username_buf = buffer_init_string(username);
|
||||
buffer *realm_buf = buffer_init_string(realm);
|
||||
int rc;
|
||||
const buffer *auth_fn;
|
||||
FILE *fp;
|
||||
|
||||
mod_authn_file_patch_connection(srv, con, p);
|
||||
rc = mod_authn_file_htdigest_get(srv, p->conf.auth_htdigest_userfile, username_buf, realm_buf, HA1);
|
||||
buffer_free(realm_buf);
|
||||
buffer_free(username_buf);
|
||||
UNUSED(con);
|
||||
return (0 == rc) ? HANDLER_GO_ON : HANDLER_ERROR;
|
||||
auth_fn = p->conf.auth_htdigest_userfile;
|
||||
if (buffer_string_is_empty(auth_fn)) return -1;
|
||||
|
||||
fp = fopen(auth_fn->ptr, "r");
|
||||
if (NULL != fp) {
|
||||
int rc = mod_authn_file_htdigest_get_loop(srv, fp, auth_fn, ai);
|
||||
fclose(fp);
|
||||
return rc;
|
||||
}
|
||||
else {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", auth_fn, "failed:", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static handler_t mod_authn_file_htdigest_digest(server *srv, connection *con, void *p_d, http_auth_info_t *ai) {
|
||||
return (0 == mod_authn_file_htdigest_get(srv, con, p_d, ai))
|
||||
? HANDLER_GO_ON
|
||||
: HANDLER_ERROR;
|
||||
}
|
||||
|
||||
static handler_t mod_authn_file_htdigest_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw) {
|
||||
plugin_data *p = (plugin_data *)p_d;
|
||||
li_MD5_CTX Md5Ctx;
|
||||
unsigned char HA1[16];
|
||||
unsigned char htdigest[16];
|
||||
|
||||
mod_authn_file_patch_connection(srv, con, p);
|
||||
if (mod_authn_file_htdigest_get(srv, p->conf.auth_htdigest_userfile, username, require->realm, htdigest)) return HANDLER_ERROR;
|
||||
http_auth_info_t ai;
|
||||
ai.dalgo = HTTP_AUTH_DIGEST_MD5;
|
||||
ai.dlen = HTTP_AUTH_DIGEST_MD5_BINLEN;
|
||||
ai.username = username->ptr;
|
||||
ai.ulen = buffer_string_length(username);
|
||||
ai.realm = require->realm->ptr;
|
||||
ai.rlen = buffer_string_length(require->realm);
|
||||
|
||||
if (mod_authn_file_htdigest_get(srv, con, p_d, &ai)) return HANDLER_ERROR;
|
||||
|
||||
li_MD5_Init(&Md5Ctx);
|
||||
li_MD5_Update(&Md5Ctx, CONST_BUF_LEN(username));
|
||||
|
@ -296,8 +301,7 @@ static handler_t mod_authn_file_htdigest_basic(server *srv, connection *con, voi
|
|||
li_MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
|
||||
li_MD5_Final(HA1, &Md5Ctx);
|
||||
|
||||
UNUSED(con);
|
||||
return (0 == memcmp(HA1, htdigest, sizeof(HA1))
|
||||
return (0 == memcmp(HA1, ai.digest, ai.dlen)
|
||||
&& http_auth_match_rules(require, username->ptr, NULL, NULL))
|
||||
? HANDLER_GO_ON
|
||||
: HANDLER_ERROR;
|
||||
|
@ -364,12 +368,13 @@ static int mod_authn_file_htpasswd_get(server *srv, const buffer *auth_fn, const
|
|||
return -1;
|
||||
}
|
||||
|
||||
static handler_t mod_authn_file_plain_digest(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]) {
|
||||
static handler_t mod_authn_file_plain_digest(server *srv, connection *con, void *p_d, http_auth_info_t *ai) {
|
||||
plugin_data *p = (plugin_data *)p_d;
|
||||
buffer *username_buf = buffer_init_string(username);
|
||||
buffer *username_buf = buffer_init();
|
||||
buffer *password_buf = buffer_init();/* password-string from auth-backend */
|
||||
int rc;
|
||||
mod_authn_file_patch_connection(srv, con, p);
|
||||
buffer_copy_string_len(username_buf, ai->username, ai->ulen);
|
||||
rc = mod_authn_file_htpasswd_get(srv, p->conf.auth_plain_userfile, username_buf, password_buf);
|
||||
if (0 == rc) {
|
||||
/* generate password from plain-text */
|
||||
|
@ -377,10 +382,10 @@ static handler_t mod_authn_file_plain_digest(server *srv, connection *con, void
|
|||
li_MD5_Init(&Md5Ctx);
|
||||
li_MD5_Update(&Md5Ctx, (unsigned char *)username_buf->ptr, buffer_string_length(username_buf));
|
||||
li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
|
||||
li_MD5_Update(&Md5Ctx, (unsigned char *)realm, strlen(realm));
|
||||
li_MD5_Update(&Md5Ctx, (unsigned char *)ai->realm, ai->rlen);
|
||||
li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
|
||||
li_MD5_Update(&Md5Ctx, (unsigned char *)password_buf->ptr, buffer_string_length(password_buf));
|
||||
li_MD5_Final(HA1, &Md5Ctx);
|
||||
li_MD5_Final(ai->digest, &Md5Ctx);
|
||||
}
|
||||
buffer_free(password_buf);
|
||||
buffer_free(username_buf);
|
||||
|
|
|
@ -135,7 +135,7 @@ static void mod_authn_mysql_sock_error(server *srv, plugin_config *pconf) {
|
|||
}
|
||||
|
||||
static handler_t mod_authn_mysql_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
|
||||
static handler_t mod_authn_mysql_digest(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]);
|
||||
static handler_t mod_authn_mysql_digest(server *srv, connection *con, void *p_d, http_auth_info_t *dig);
|
||||
|
||||
INIT_FUNC(mod_authn_mysql_init) {
|
||||
static http_auth_backend_t http_auth_backend_mysql =
|
||||
|
@ -387,7 +387,7 @@ static int mod_authn_mysql_password_cmp(const char *userpw, unsigned long userpw
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int mod_authn_mysql_result(server *srv, plugin_data *p, const char *pw, unsigned char HA1[16]) {
|
||||
static int mod_authn_mysql_result(server *srv, plugin_data *p, http_auth_info_t *ai, const char *pw) {
|
||||
MYSQL_RES *result = mysql_store_result(p->conf.mysql_conn);
|
||||
int rc = -1;
|
||||
my_ulonglong num_rows;
|
||||
|
@ -413,8 +413,11 @@ static int mod_authn_mysql_result(server *srv, plugin_data *p, const char *pw, u
|
|||
rc = mod_authn_mysql_password_cmp(row[0], lengths[0], pw);
|
||||
}
|
||||
else { /* used with HTTP Digest auth */
|
||||
rc = http_auth_digest_hex2bin(row[0], lengths[0],
|
||||
HA1, sizeof(HA1));
|
||||
/*(currently supports only single row, single digest algorithm)*/
|
||||
if (lengths[0] == (ai->dlen << 1)) {
|
||||
rc = http_auth_digest_hex2bin(row[0], lengths[0],
|
||||
ai->digest, sizeof(ai->digest));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (0 == num_rows) {
|
||||
|
@ -428,7 +431,7 @@ static int mod_authn_mysql_result(server *srv, plugin_data *p, const char *pw, u
|
|||
return rc;
|
||||
}
|
||||
|
||||
static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d, const char *username, const char *realm, const char *pw, unsigned char HA1[16]) {
|
||||
static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d, http_auth_info_t *ai, const char *pw) {
|
||||
plugin_data *p = (plugin_data *)p_d;
|
||||
int rc = -1;
|
||||
|
||||
|
@ -443,14 +446,12 @@ static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d,
|
|||
}
|
||||
|
||||
do {
|
||||
size_t unamelen = strlen(username);
|
||||
size_t urealmlen = strlen(realm);
|
||||
char q[1024], uname[512], urealm[512];
|
||||
unsigned long mrc;
|
||||
|
||||
if (unamelen > sizeof(uname)/2-1)
|
||||
if (ai->ulen > sizeof(uname)/2-1)
|
||||
return HANDLER_ERROR;
|
||||
if (urealmlen > sizeof(urealm)/2-1)
|
||||
if (ai->rlen > sizeof(urealm)/2-1)
|
||||
return HANDLER_ERROR;
|
||||
|
||||
if (!mod_authn_mysql_sock_acquire(srv, &p->conf)) {
|
||||
|
@ -458,20 +459,20 @@ static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d,
|
|||
}
|
||||
|
||||
#if 0
|
||||
mrc = mysql_real_escape_string_quote(p->conf.mysql_conn,uname,username,
|
||||
(unsigned long)unamelen, '\'');
|
||||
mrc = mysql_real_escape_string_quote(p->conf.mysql_conn, uname,
|
||||
ai->username, ai->ulen, '\'');
|
||||
if ((unsigned long)~0 == mrc) break;
|
||||
|
||||
mrc = mysql_real_escape_string_quote(p->conf.mysql_conn,urealm,realm,
|
||||
(unsigned long)urealmlen, '\'');
|
||||
mrc = mysql_real_escape_string_quote(p->conf.mysql_conn, urealm,
|
||||
ai->realm, ai->rlen, '\'');
|
||||
if ((unsigned long)~0 == mrc) break;
|
||||
#else
|
||||
mrc = mysql_real_escape_string(p->conf.mysql_conn, uname,
|
||||
username, (unsigned long)unamelen);
|
||||
ai->username, ai->ulen);
|
||||
if ((unsigned long)~0 == mrc) break;
|
||||
|
||||
mrc = mysql_real_escape_string(p->conf.mysql_conn, urealm,
|
||||
realm, (unsigned long)urealmlen);
|
||||
ai->realm, ai->rlen);
|
||||
if ((unsigned long)~0 == mrc) break;
|
||||
#endif
|
||||
|
||||
|
@ -512,7 +513,7 @@ static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d,
|
|||
}
|
||||
}
|
||||
|
||||
rc = mod_authn_mysql_result(srv, p, pw, HA1);
|
||||
rc = mod_authn_mysql_result(srv, p, ai, pw);
|
||||
|
||||
} while (0);
|
||||
|
||||
|
@ -522,19 +523,23 @@ static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d,
|
|||
}
|
||||
|
||||
static handler_t mod_authn_mysql_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw) {
|
||||
/*(HA1 is not written since pw passed should not be NULL;
|
||||
* avoid passing NULL since subroutine expects unsigned char HA1[16] arg)*/
|
||||
static unsigned char HA1[16];
|
||||
char *realm = require->realm->ptr;
|
||||
handler_t rc =mod_authn_mysql_query(srv,con,p_d,username->ptr,realm,pw,HA1);
|
||||
handler_t rc;
|
||||
http_auth_info_t ai;
|
||||
ai.dalgo = HTTP_AUTH_DIGEST_NONE;
|
||||
ai.dlen = 0;
|
||||
ai.username = username->ptr;
|
||||
ai.ulen = buffer_string_length(username);
|
||||
ai.realm = require->realm->ptr;
|
||||
ai.rlen = buffer_string_length(require->realm);
|
||||
rc = mod_authn_mysql_query(srv, con, p_d, &ai, pw);
|
||||
if (HANDLER_GO_ON != rc) return rc;
|
||||
return http_auth_match_rules(require, username->ptr, NULL, NULL)
|
||||
? HANDLER_GO_ON /* access granted */
|
||||
: HANDLER_ERROR;
|
||||
}
|
||||
|
||||
static handler_t mod_authn_mysql_digest(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]) {
|
||||
return mod_authn_mysql_query(srv,con,p_d,username,realm,NULL,HA1);
|
||||
static handler_t mod_authn_mysql_digest(server *srv, connection *con, void *p_d, http_auth_info_t *ai) {
|
||||
return mod_authn_mysql_query(srv, con, p_d, ai, NULL);
|
||||
}
|
||||
|
||||
int mod_authn_mysql_plugin_init(plugin *p);
|
||||
|
|
Loading…
Reference in New Issue