mod_authz_core.c 36.8 KB
Newer Older
powelld's avatar
powelld committed

/*
 * method authz provider
 */

static authz_status method_check_authorization(request_rec *r,
                                               const char *require_line,
                                               const void *parsed_require_line)
{
    const apr_int64_t *allowed = parsed_require_line;
    if (*allowed & (AP_METHOD_BIT << r->method_number))
        return AUTHZ_GRANTED;
    else
        return AUTHZ_DENIED;
}

static const char *method_parse_config(cmd_parms *cmd, const char *require_line,
                                       const void **parsed_require_line)
{
    const char *w, *t;
    apr_int64_t *allowed = apr_pcalloc(cmd->pool, sizeof(apr_int64_t));

    t = require_line;

    while ((w = ap_getword_conf(cmd->temp_pool, &t)) && w[0]) {
        int m = ap_method_number_of(w);
        if (m == M_INVALID) {
            return apr_pstrcat(cmd->pool, "Invalid Method '", w, "'", NULL);
        }

        *allowed |= (AP_METHOD_BIT << m);
    }

    *parsed_require_line = allowed;
    return NULL;
}

static const authz_provider authz_method_provider =
{
    &method_check_authorization,
    &method_parse_config,
};

/*
 * expr authz provider
 */

#define REQUIRE_EXPR_NOTE "Require_expr_info"
struct require_expr_info {
    ap_expr_info_t *expr;
    int want_user;
};

static int expr_lookup_fn(ap_expr_lookup_parms *parms)
{
    if (parms->type == AP_EXPR_FUNC_VAR
        && strcasecmp(parms->name, "REMOTE_USER") == 0) {
        struct require_expr_info *info;
        apr_pool_userdata_get((void**)&info, REQUIRE_EXPR_NOTE, parms->ptemp);
        AP_DEBUG_ASSERT(info != NULL);
        info->want_user = 1;
    }
    return ap_expr_lookup_default(parms);
}

static const char *expr_parse_config(cmd_parms *cmd, const char *require_line,
                                     const void **parsed_require_line)
{
    const char *expr_err = NULL;
    struct require_expr_info *info = apr_pcalloc(cmd->pool, sizeof(*info));

    /* if the expression happens to be surrounded by quotes, skip them */
    if (require_line[0] == '"') {
        apr_size_t len = strlen(require_line);

        if (require_line[len-1] == '"')
            require_line = apr_pstrndup(cmd->temp_pool,
                                        require_line + 1,
                                        len - 2);
    }

    apr_pool_userdata_setn(info, REQUIRE_EXPR_NOTE, apr_pool_cleanup_null,
                          cmd->temp_pool);
    info->expr = ap_expr_parse_cmd(cmd, require_line, 0, &expr_err,
                                   expr_lookup_fn);

    if (expr_err)
        return apr_pstrcat(cmd->temp_pool,
                           "Cannot parse expression in require line: ",
                           expr_err, NULL);

    *parsed_require_line = info;

    return NULL;
}

static authz_status expr_check_authorization(request_rec *r,
                                             const char *require_line,
                                             const void *parsed_require_line)
{
    const char *err = NULL;
    const struct require_expr_info *info = parsed_require_line;
    int rc = ap_expr_exec(r, info->expr, &err);

    if (rc < 0) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02320)
                      "Error evaluating expression in 'Require expr': %s",
                      err);
        return AUTHZ_GENERAL_ERROR;
    }
    else if (rc == 0) {
        if (info->want_user)
            return AUTHZ_DENIED_NO_USER;
        else
            return AUTHZ_DENIED;
    }
    else {
        return AUTHZ_GRANTED;
    }
}

static const authz_provider authz_expr_provider =
{
    &expr_check_authorization,
    &expr_parse_config,
};


static void register_hooks(apr_pool_t *p)
{
    APR_REGISTER_OPTIONAL_FN(authz_some_auth_required);

    ap_hook_pre_config(authz_core_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_check_config(authz_core_check_config, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_check_authz(authorize_user, NULL, NULL, APR_HOOK_LAST,
                        AP_AUTH_INTERNAL_PER_CONF);
    ap_hook_check_access_ex(authorize_userless, NULL, NULL, APR_HOOK_LAST,
                            AP_AUTH_INTERNAL_PER_CONF);

    ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "env",
                              AUTHZ_PROVIDER_VERSION,
                              &authz_env_provider, AP_AUTH_INTERNAL_PER_CONF);
    ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "all",
                              AUTHZ_PROVIDER_VERSION,
                              &authz_all_provider, AP_AUTH_INTERNAL_PER_CONF);
    ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "method",
                              AUTHZ_PROVIDER_VERSION,
                              &authz_method_provider, AP_AUTH_INTERNAL_PER_CONF);
    ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "expr",
                              AUTHZ_PROVIDER_VERSION,
                              &authz_expr_provider, AP_AUTH_INTERNAL_PER_CONF);
}

AP_DECLARE_MODULE(authz_core) =
{
    STANDARD20_MODULE_STUFF,
    create_authz_core_dir_config,   /* dir config creater */
    merge_authz_core_dir_config,    /* dir merger */
    create_authz_core_svr_config,   /* server config */
    merge_authz_core_svr_config ,   /* merge server config */
    authz_cmds,
    register_hooks                  /* register hooks */
};