From: Ronald Tschalar Date: Thu, 4 Nov 1999 06:09:54 +0000 (+0000) Subject: First cut at port to apache-2.0. Simple tests are working. X-Git-Tag: 1.3.10~188 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c4ae1f9289358d37f720f190645e5574c1b1db67;p=thirdparty%2Fapache%2Fhttpd.git First cut at port to apache-2.0. Simple tests are working. Error handling is still not quite clear in some cases (especially in conjunction with ap_pcfg_openfile), and random-number generation still needs to be moved into APR. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@84098 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/aaa/mod_auth_digest.c b/modules/aaa/mod_auth_digest.c index 314a0645e5f..a198610b4d8 100644 --- a/modules/aaa/mod_auth_digest.c +++ b/modules/aaa/mod_auth_digest.c @@ -130,6 +130,12 @@ #include "util_uri.h" #include "util_md5.h" #include "ap_sha1.h" + +#ifdef WIN32 +/* Crypt APIs are available on Win95 with OSR 2 */ +#include +#endif + #ifdef HAVE_SHMEM_MM #include "mm.h" #endif /* HAVE_SHMEM_MM */ @@ -160,7 +166,7 @@ typedef struct digest_config_struct { #define NONCE_TIME_LEN (((sizeof(time_t)+2)/3)*4) -#define NONCE_HASH_LEN 40 +#define NONCE_HASH_LEN (2*SHA_DIGESTSIZE) #define NONCE_LEN (NONCE_TIME_LEN + NONCE_HASH_LEN) #define SECRET_LEN 20 @@ -172,12 +178,12 @@ typedef struct hash_entry { unsigned long key; /* the key for this entry */ struct hash_entry *next; /* next entry in the bucket */ unsigned long nonce_count; /* for nonce-count checking */ - char ha1[17]; /* for algorithm=MD5-sess */ + char ha1[2*MD5_DIGESTSIZE+1]; /* for algorithm=MD5-sess */ char last_nonce[NONCE_LEN+1]; /* for one-time nonce's */ } client_entry; static struct hash_table { - client_entry **table; + client_entry **ap_table_t; unsigned long tbl_len; unsigned long num_entries; unsigned long num_created; @@ -249,7 +255,7 @@ module MODULE_VAR_EXPORT digest_auth_module; */ #ifdef HAVE_SHMEM_MM -static void cleanup_tables(void *not_used) +static ap_status_t cleanup_tables(void *not_used) { fprintf(stderr, "Digest: cleaning up shared memory\n"); fflush(stderr); @@ -268,43 +274,64 @@ static void cleanup_tables(void *not_used) mm_destroy(otn_count_mm); otn_count_mm = NULL; } + + return APR_SUCCESS; } #endif /* HAVE_SHMEM_MM */ +#ifdef WIN32 +/* TODO: abstract out the random number generation. APR? */ +static void initialize_secret(server_rec *s) +{ + HCRYPTPROV hProv; + + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, s, + "Digest: generating secret for digest authentication ..."); + if (!CryptAcquireContext(&hProv,NULL,NULL,PROV_RSA_FULL,0)) { + ap_log_error(APLOG_MARK, APLOG_CRIT, s, + "Digest: Error acquiring context. Errno = %d", + GetLastError()); + exit(EXIT_FAILURE); + } + if (!CryptGenRandom(hProv,sizeof(secret),secret)) { + ap_log_error(APLOG_MARK, APLOG_CRIT, s, + "Digest: Error generating secret. Errno = %d", + GetLastError()); + exit(EXIT_FAILURE); + } + + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, s, "Digest: done"); +} +#else static void initialize_secret(server_rec *s) { #ifdef DEV_RANDOM - FILE *rnd; + int rnd; size_t got, tot; #else extern int randbyte(void); /* from the truerand library */ unsigned int idx; #endif - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, s, + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, s, "Digest: generating secret for digest authentication ..."); #ifdef DEV_RANDOM #define XSTR(x) #x #define STR(x) XSTR(x) - if ((rnd = fopen(STR(DEV_RANDOM), "rb")) == NULL) { + if ((rnd = open(STR(DEV_RANDOM), O_RDONLY)) == NULL) { ap_log_error(APLOG_MARK, APLOG_CRIT, s, "Digest: Couldn't open " STR(DEV_RANDOM)); exit(EXIT_FAILURE); } - if (setvbuf(rnd, NULL, _IONBF, 0) != 0) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_CRIT, s, - "Digest: Error trying to disable buffering for " STR(DEV_RANDOM)); - exit(EXIT_FAILURE); - } for (tot=0; totserver, + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, cmd->server, "Digest: WARNING: qop `auth-int' currently only works " "correctly for responses with no entity"); else if (strcasecmp(op, "auth")) @@ -559,7 +587,7 @@ static const char *set_algorithm(cmd_parms *cmd, void *config, const char *alg) #ifdef HAVE_SHMEM_MM ; #else /* HAVE_SHMEM_MM */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, cmd->server, + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, cmd->server, "Digest: WARNING: algorithm `MD5-sess' is currently not " "correctly implemented"); #endif /* HAVE_SHMEM_MM */ @@ -909,7 +937,7 @@ static int get_digest_rec(request_rec *r, digest_header_rec *resp) * Note that this must be called after mod_proxy had its go so that * r->proxyreq is set correctly. */ -static int update_nonce_count(request_rec *r) +static int parse_hdr_and_update_nc(request_rec *r) { digest_header_rec *resp; int res; @@ -969,7 +997,7 @@ static void gen_nonce_hash(char *hash, const char *timestr, const char *opaque, /* The nonce has the format b64(time)+hash . */ -static const char *gen_nonce(pool *p, time_t now, const char *opaque, +static const char *gen_nonce(ap_context_t *p, time_t now, const char *opaque, const server_rec *server, const digest_config_rec *conf) { @@ -1075,12 +1103,12 @@ static const char *get_session(const request_rec *r, if (ha1 == NULL || ha1[0] == '\0') { urp = get_userpw_hash(r, resp, conf); ha1 = ap_md5(r->pool, - (unsigned char *) ap_pstrcat(r->pool, ha1, ":", resp->nonce, + (unsigned char *) ap_pstrcat(r->pool, urp, ":", resp->nonce, ":", resp->cnonce, NULL)); if (!resp->client) resp->client = gen_client(r); if (resp->client) - memcpy(resp->client->ha1, ha1, 17); + memcpy(resp->client->ha1, ha1, sizeof(resp->client->ha1)); } return ha1; @@ -1098,8 +1126,8 @@ static void clear_session(const digest_header_rec *resp) * Authorization challenge generation code (for WWW-Authenticate) */ -static const char *guess_domain(pool *p, const char *uri, const char *filename, - const char *dir) +static const char *guess_domain(ap_context_t *p, const char *uri, + const char *filename, const char *dir) { size_t u_len = strlen(uri), f_len = strlen(filename), d_len = strlen(dir); const char *u, *f; @@ -1163,7 +1191,7 @@ static const char *guess_domain(pool *p, const char *uri, const char *filename, } -static const char *ltox(pool *p, unsigned long num) +static const char *ltox(ap_context_t *p, unsigned long num) { if (num != 0) return ap_psprintf(p, "%lx", num); @@ -1241,14 +1269,16 @@ static void note_digest_auth_failure(request_rec *r, * unneccessarily (it's usually > 200 bytes!). */ - if (conf->uri_list) + if (r->proxyreq) + domain = NULL; /* don't send domain for proxy requests */ + else if (conf->uri_list) domain = conf->uri_list; else { /* They didn't specify any domain, so let's guess at it */ domain = guess_domain(r->pool, resp->request_uri->path, r->filename, conf->dir_name); if (domain[0] == '/' && domain[1] == '\0') - domain = ""; /* "/" is the default, so no need to send it */ + domain = NULL; /* "/" is the default, so no need to send it */ else domain = ap_pstrcat(r->pool, ", domain=\"", domain, "\"", NULL); } @@ -1275,8 +1305,9 @@ static const char *get_hash(request_rec *r, const char *user, char l[MAX_STRING_LEN]; const char *rpw; char *w, *x; + ap_status_t sts; - if (!(f = ap_pcfg_openfile(r->pool, auth_pwfile))) { + if ((sts = ap_pcfg_openfile(&f, r->pool, auth_pwfile)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, "Digest: Could not open password file: %s", auth_pwfile); return NULL; @@ -1370,7 +1401,7 @@ static int check_nonce(request_rec *r, digest_header_rec *resp, if (dt > conf->nonce_lifetime) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0,r, "Digest: user %s: nonce expired - sending new nonce", - r->connection->user); + r->user); note_digest_auth_failure(r, conf, resp, 1); return AUTH_REQUIRED; } @@ -1379,7 +1410,7 @@ static int check_nonce(request_rec *r, digest_header_rec *resp, if (memcmp(resp->client->last_nonce, resp->nonce, NONCE_LEN)) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r, "Digest: user %s: one-time-nonce mismatch - sending " - "new nonce", r->connection->user); + "new nonce", r->user); note_digest_auth_failure(r, conf, resp, 1); return AUTH_REQUIRED; } @@ -1451,7 +1482,6 @@ static int authenticate_digest_user(request_rec *r) digest_config_rec *conf; digest_header_rec *resp; request_rec *mainreq; - conn_rec *conn = r->connection; const char *t; int res; @@ -1500,21 +1530,39 @@ static int authenticate_digest_user(request_rec *r) return AUTH_REQUIRED; } - r->connection->user = (char *) resp->username; - r->connection->ap_auth_type = (char *) "Digest"; + r->user = (char *) resp->username; + r->ap_auth_type = (char *) "Digest"; /* check the auth attributes */ if (strcmp(resp->uri, resp->request_uri->path)) { uri_components *r_uri = resp->request_uri, d_uri; - ap_parse_uri_components(r->pool, resp->uri, &d_uri); + int port; + + if (ap_parse_uri_components(r->pool, resp->uri, &d_uri) != HTTP_OK) { + ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, + "Digest: invalid uri <%s> in Authorization header", + resp->uri); + return BAD_REQUEST; + } + + if (d_uri.hostname) + ap_unescape_url(d_uri.hostname); + if (d_uri.path) + ap_unescape_url(d_uri.path); + if (d_uri.query) + ap_unescape_url(d_uri.query); + if (r_uri->query) + ap_unescape_url(r_uri->query); + port = ap_get_server_port(r); if ((d_uri.hostname && d_uri.hostname[0] != '\0' - && strcasecmp(d_uri.hostname, r->server->server_hostname)) - || (d_uri.port_str && d_uri.port != r->server->port) - || (!d_uri.port_str && r->server->port != 80) - || strcmp(d_uri.path, r_uri->path) + && strcasecmp(d_uri.hostname, ap_get_server_name(r))) + || (d_uri.port_str && d_uri.port != port) + || (d_uri.hostname && d_uri.hostname[0] != '\0' + && !d_uri.port_str && port != ap_default_port(r)) + || !d_uri.path || strcmp(d_uri.path, r_uri->path) || (d_uri.query != r_uri->query && (!d_uri.query || !r_uri->query || strcmp(d_uri.query, r_uri->query))) @@ -1556,10 +1604,10 @@ static int authenticate_digest_user(request_rec *r) if (!conf->pwfile) return DECLINED; - if (!(conf->ha1 = get_hash(r, conn->user, conf->realm, conf->pwfile))) { + if (!(conf->ha1 = get_hash(r, r->user, conf->realm, conf->pwfile))) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, "Digest: user `%s' in realm `%s' not found: %s", - conn->user, conf->realm, r->uri); + r->user, conf->realm, r->uri); note_digest_auth_failure(r, conf, resp, 0); return AUTH_REQUIRED; } @@ -1568,7 +1616,7 @@ static int authenticate_digest_user(request_rec *r) /* old (rfc-2069) style digest */ if (strcmp(resp->digest, old_digest(r, resp, conf->ha1))) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: user %s: password mismatch: %s", conn->user, + "Digest: user %s: password mismatch: %s", r->user, r->uri); note_digest_auth_failure(r, conf, resp, 0); return AUTH_REQUIRED; @@ -1595,7 +1643,7 @@ static int authenticate_digest_user(request_rec *r) if (strcmp(resp->digest, new_digest(r, resp, conf))) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Digest: user %s: password mismatch: %s", conn->user, + "Digest: user %s: password mismatch: %s", r->user, r->uri); note_digest_auth_failure(r, conf, resp, 0); return AUTH_REQUIRED; @@ -1620,16 +1668,17 @@ static int authenticate_digest_user(request_rec *r) * Checking ID */ -static table *groups_for_user(request_rec *r, const char *user, +static ap_table_t *groups_for_user(request_rec *r, const char *user, const char *grpfile) { configfile_t *f; - table *grps = ap_make_table(r->pool, 15); + ap_table_t *grps = ap_make_table(r->pool, 15); ap_context_t *sp; char l[MAX_STRING_LEN]; const char *group_name, *ll, *w; + ap_status_t sts; - if (!(f = ap_pcfg_openfile(r->pool, grpfile))) { + if ((sts = ap_pcfg_openfile(&f, r->pool, grpfile)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, "Digest: Could not open group file: %s", grpfile); return NULL; @@ -1666,13 +1715,13 @@ static int digest_check_auth(request_rec *r) const digest_config_rec *conf = (digest_config_rec *) ap_get_module_config(r->per_dir_config, &digest_auth_module); - const char *user = r->connection->user; + const char *user = r->user; int m = r->method_number; int method_restricted = 0; register int x; const char *t, *w; - table *grpstatus; - const array_header *reqs_arr; + ap_table_t *grpstatus; + const ap_array_header_t *reqs_arr; require_line *reqs; if (!(t = ap_auth_type(r)) || strcasecmp(t, "Digest")) @@ -1746,7 +1795,7 @@ static int digest_check_auth(request_rec *r) */ #ifdef SEND_DIGEST -static const char *hdr(const table *tbl, const char *name) +static const char *hdr(const ap_table_t *tbl, const char *name) { const char *val = ap_table_get(tbl, name); if (val) @@ -1895,26 +1944,27 @@ static int add_auth_info(request_rec *r) } +static void register_hooks(void) +{ + static const char * const cfgPost[]={ "http_core.c", NULL }; + static const char * const parsePre[]={ "mod_proxy.c", NULL }; + + ap_hook_post_config(initialize_module, NULL, cfgPost, NULL); + ap_hook_post_read_request(parse_hdr_and_update_nc, parsePre, NULL, NULL); + ap_hook_check_user_id(authenticate_digest_user, NULL, NULL, HOOK_MIDDLE); + ap_hook_auth_checker(digest_check_auth, NULL, NULL, HOOK_MIDDLE); + ap_hook_fixups(add_auth_info, NULL, NULL, HOOK_MIDDLE); +} + module MODULE_VAR_EXPORT digest_auth_module = { - STANDARD_MODULE_STUFF, - initialize_module, /* initializer */ + STANDARD20_MODULE_STUFF, create_digest_dir_config, /* dir config creater */ NULL, /* dir merger --- default is to override */ NULL, /* server config */ NULL, /* merge server config */ digest_cmds, /* command table */ NULL, /* handlers */ - NULL, /* filename translation */ - authenticate_digest_user, /* check_user_id */ - digest_check_auth, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - add_auth_info, /* fixups */ - NULL, /* logger */ - NULL, /* header parser */ - NULL, /* child_init */ - NULL, /* child_exit */ - update_nonce_count /* post read-request */ + register_hooks /* register hooks */ };