#include "httpd.h" #include "http_config.h" #include "http_core.h" #include "http_log.h" #include "http_request.h" #include "http_protocol.h" #include "mod_auth.h" #include "ap_provider.h" #include "apr_strings.h" #include "util_md5.h" module AP_MODULE_DECLARE_DATA authnz_day_module; typedef struct { int nopassword; int authoritative; } authnz_day_rec; static authn_status authn_check_day(request_rec *r, const char* user, const char* password) { int y, m, d; apr_time_exp_t today; const char* const wdays[7] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" }; authnz_day_rec *cfg = ap_get_module_config(r->per_dir_config, &authnz_day_module); /* get today's date, in localtime. If this fails it's a server error */ if (apr_time_exp_lt(&today, apr_time_now()) != APR_SUCCESS) { return AUTH_GENERAL_ERROR; } /* check the username is today */ /* If not, disclaim any interest in this request */ if ((strlen(user) < 3) || strncasecmp(user, wdays[today.tm_wday], 3)) { return AUTH_USER_NOT_FOUND; } /* unless we're configured to ignore password, check this */ if (!cfg->nopassword) { /* read password, and reject anything not in 2005-11-03 format */ if (sscanf(password, "%d-%d-%d", &y, &m, &d) != 3) { return AUTH_DENIED; } /* check the password is today */ if ((y != (today.tm_year+1900)) || (m != (today.tm_mon+1)) || (d != today.tm_mday)) { return AUTH_DENIED; } } /* OK, we're happy */ return AUTH_GRANTED; } static authn_status authn_digest_day(request_rec *r, const char* user, const char* realm, char** hash) { const char* unencoded; apr_time_exp_t today; const char* const wdays[7] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" }; /* get today's date, in localtime. If this fails it's a server error */ if (apr_time_exp_lt(&today, apr_time_now()) != APR_SUCCESS) { return AUTH_GENERAL_ERROR; } /* check the username is today (MUST be an exact match this time */ /* If not, disclaim any interest in this request */ if (strcmp(user, wdays[today.tm_wday])) { return AUTH_USER_NOT_FOUND; } /* Now compute the MD5 hash of user:realm:password * which in our scheme of things is day:realm:date */ unencoded = apr_psprintf(r->pool, "%s:%s:%4.4d-%2.2d-%2.2d", wdays[today.tm_wday], realm, today.tm_year+1900, today.tm_mon+1, today.tm_mday); *hash = ap_md5(r->pool, unencoded); /* OK, we're happy. Note this isn't GRANTED as it was with Basic * Authentication, because we only 'looked up' the password, but * haven't verified it. */ return AUTH_USER_FOUND; } static const authn_provider authn_day_provider = { &authn_check_day, &authn_digest_day }; static int authz_day(request_rec *r) { authnz_day_rec *cfg = ap_get_module_config(r->per_dir_config, &authnz_day_module); char *day = r->user; int m = r->method_number; const apr_array_header_t *reqs_arr = ap_requires(r); require_line *reqs = reqs_arr ? (require_line *) reqs_arr->elts : NULL; char *w; const char *t; int i; int have_day = 0; if (strlen(day) < 3) { return DECLINED; } if (!reqs_arr) { return DECLINED; } /* Go through applicable Require directives */ for (i = 0; i < reqs_arr->nelts; ++i) { /* Ignore this Require if it's in a section * that exclude this method */ if (!(reqs[i].method_mask & (AP_METHOD_BIT << m))) { continue; } /* ignore if it's not a "Require day ..." */ t = reqs[i].requirement; w = ap_getword_white(r->pool, &t); if (strcasecmp(w, "day")) { continue; } /* OK, we have a "Require day" to satisfy */ have_day = 1; /* Loop over allowed days and match to today */ while (*t) { w = ap_getword_white(r->pool, &t); if ((strlen(w) >= 3) && !strncasecmp(w, day, 3)) { /* Yep, anonymous access is allowed today */ return OK; } } } /* If there weren't any "Require day" directives, we're irrelevant */ if (!have_day) { return DECLINED; } /* If we're not authoritative, hand over to other authz modules */ if (!cfg->authoritative) { return DECLINED; } /* OK, our decision is final and binding */ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Anonymous usage closed on %s", day); ap_note_auth_failure(r); return HTTP_UNAUTHORIZED; } static void register_hooks(apr_pool_t *p) { static const char *const aszSucc[] = { "mod_authz_user.c", NULL }; ap_register_provider(p, AUTHN_PROVIDER_GROUP, "day", "0", &authn_day_provider); ap_hook_auth_checker(authz_day, NULL, aszSucc, APR_HOOK_MIDDLE); } static void *authnz_day_cr_conf(apr_pool_t *pool, char *x) { return apr_pcalloc(pool, sizeof(authnz_day_rec)); } static const command_rec authnz_day_cmds[] = { AP_INIT_FLAG("AuthnDayIgnorePassword", ap_set_flag_slot, (void *)APR_OFFSETOF(authnz_day_rec, nopassword), OR_AUTHCFG, "Set 'On' to ignore password; 'Off' (default) to require " "current date in 2005-11-03 format as a password."), AP_INIT_FLAG("AuthzDayAuthoritative", ap_set_flag_slot, (void *)APR_OFFSETOF(authnz_day_rec, authoritative), OR_AUTHCFG, "Set 'On' to reject if anonymous access isn't allowed today; " "'Off' (default) to allow checking against other methods too."), {NULL} }; module AP_MODULE_DECLARE_DATA authnz_day_module = { STANDARD20_MODULE_STUFF, authnz_day_cr_conf, /* dir config creater */ NULL, /* dir merger --- default is to override */ NULL, /* server config */ NULL, /* merge server config */ authnz_day_cmds, /* command apr_table_t */ register_hooks /* register hooks */ };