/* ** ** Copyright (c) 2010 - Issac Goldstand All rights reserved ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. ** ** “Adobe” and “the Adobe logo” are either registered trademarks or trademarks ** of Adobe Systems Incorporated in the United States and/or other countries. ** ** mod_adobe_crossdomainpolicy.c -- A Protocol Module for the Adobe® Policy File Server ** [Autogenerated via ``apxs -n adobe_crossdomainpolicy -g''] ** ** To play with this sample module first compile it into a ** DSO file and install it into Apache's modules directory ** by running: ** ** $ apxs -c -i mod_adobe_crossdomainpolicy.c ** ** Then activate it in Apache's httpd.conf file for instance ** for the URL /adobe_crossdomainpolicy in as follows: ** ** # httpd.conf ** LoadModule adobe_crossdomainpolicy_module modules/mod_adobe_crossdomainpolicy.so ** Listen 843 ** ** AdobePolicyFileServerEnabled On ** AdobePolicyFile /var/www/crossdomain.xml ** ** ** Then after restarting Apache via ** ** $ apachectl restart ** ** you immediately can request the cross domain policy and watch for the ** output of this module. This can be achieved for instance via: ** ** $ perl -e 'printf "%c",0' | nc 127.0.0.1 843 ** ** The output should be similar to the following: ** ** ** ** ** ** ** ** ** ** ** */ #include "httpd.h" #define CORE_PRIVATE #include "http_config.h" #include "http_connection.h" #include "http_protocol.h" #include "ap_config.h" #include "http_log.h" #include "apr.h" #include "apr_pools.h" #include "apr_buckets.h" #include "http_core.h" #include "apr_strings.h" #include "apr_file_io.h" #include "apr_file_info.h" #include #define POLICY_FILE_REQUEST "" #define DEFAULT_POLICY "\n\ \n\ \n\ \n\ \n\ \n\ \n\ " module AP_MODULE_DECLARE_DATA adobe_crossdomainpolicy_module; typedef struct { int enabled; int enabled_set; char *policyfile; int policyfile_set; } adobe_crossdomainpolicy_module_config_t; static int process_connection(conn_rec *c) { adobe_crossdomainpolicy_module_config_t *conf; apr_pool_t *p; apr_bucket_brigade *tmp_bb; apr_bucket *b; server_rec *s = c->base_server; apr_status_t rv; apr_byte_t *data; apr_size_t size = strlen(POLICY_FILE_REQUEST) + 1; // extra null apr_finfo_t finfo; apr_file_t *fd; int file_ok = 1; conf = (adobe_crossdomainpolicy_module_config_t *)ap_get_module_config(c->base_server->module_config, &adobe_crossdomainpolicy_module); if (!conf) { /* We're not configured. Something's very wrong. Abort. */ return DECLINED; } if (!conf->enabled) { /* We're configured, but disabled */ return DECLINED; } ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0,c, "I got a connection!"); if (apr_pool_create(&p, c->pool) != APR_SUCCESS) return DECLINED; tmp_bb = apr_brigade_create(p, c->bucket_alloc); apr_brigade_cleanup(tmp_bb); // Read the request rv = ap_get_brigade(c->input_filters, tmp_bb, AP_MODE_READBYTES, APR_BLOCK_READ, size); ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0,c, "Read %d bytes", size); if (rv != APR_SUCCESS) { apr_brigade_destroy(tmp_bb); return OK; } // Flatten the string into a char* if (apr_brigade_pflatten(tmp_bb, (char **)&data, &size, p) != APR_SUCCESS) { apr_brigade_destroy(tmp_bb); return OK; } apr_brigade_destroy(tmp_bb); // Did we read enough bytes? Is it a valid request if (size != strlen(POLICY_FILE_REQUEST) + 1 || // add a byte for the trailing NULL strcmp(data, POLICY_FILE_REQUEST)) { ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0,c, "Invalid request: %s (%d bytes)", data, size); return OK; } ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "Got valid request"); file_ok = 1; if (conf->policyfile == NULL || apr_stat(&finfo, conf->policyfile, APR_FINFO_SIZE, p) != APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, "Policy file does not exist: %s", conf->policyfile); file_ok = 0; } else { if ((rv = apr_file_open(&fd, conf->policyfile, APR_READ, APR_OS_DEFAULT, p)) != APR_SUCCESS) { file_ok = 0; apr_file_close(fd); ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, "File permissions deny server access: %s",conf->policyfile); } } tmp_bb = apr_brigade_create(p, c->bucket_alloc); apr_brigade_cleanup(tmp_bb); if (file_ok) { // Large file hnadling taken from mod_asis.c #if APR_HAS_LARGE_FILES if (finfo.size > AP_MAX_SENDFILE) { /* APR_HAS_LARGE_FILES issue; must split into mutiple buckets, * no greater than MAX(apr_size_t), and more granular than that * in case the brigade code/filters attempt to read it directly. */ apr_off_t fsize = finfo.size; b = apr_bucket_file_create(fd, 0, AP_MAX_SENDFILE, p, c->bucket_alloc); while (fsize > AP_MAX_SENDFILE) { APR_BRIGADE_INSERT_TAIL(tmp_bb, b); apr_bucket_copy(b, &b); b->start += AP_MAX_SENDFILE; fsize -= AP_MAX_SENDFILE; } b->length = (apr_size_t)fsize; /* Resize just the last bucket */ } else #endif b = apr_bucket_file_create(fd, 0, (apr_size_t) (finfo.size), p, c->bucket_alloc); } else { b = apr_bucket_heap_create(DEFAULT_POLICY, strlen(DEFAULT_POLICY), NULL, c->bucket_alloc); } APR_BRIGADE_INSERT_TAIL(tmp_bb, b); b = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(tmp_bb, b); rv = ap_pass_brigade(c->output_filters, tmp_bb); apr_brigade_destroy(tmp_bb); if (rv != APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, "Unknown error writing output"); } return OK; } /* -------------------------------------------------------------- */ /* Setup configurable data */ static void *create_adobe_crossdomainpolicy_config(apr_pool_t *p, server_rec *s) { adobe_crossdomainpolicy_module_config_t *ps = apr_pcalloc(p, sizeof(*ps)); ps->enabled = 0; ps->enabled_set = 0; ps->policyfile = NULL; ps->policyfile_set = 0; return ps; } static void *merge_adobe_crossdomainpolicy_config(apr_pool_t *p, void *basev, void *overridesv) { adobe_crossdomainpolicy_module_config_t *ps = apr_pcalloc(p, sizeof(*ps)); adobe_crossdomainpolicy_module_config_t *base = (adobe_crossdomainpolicy_module_config_t *) basev; adobe_crossdomainpolicy_module_config_t *overrides = (adobe_crossdomainpolicy_module_config_t *) overridesv; ps->enabled = (overrides->enabled_set == 0) ? base->enabled : overrides->enabled; ps->policyfile = (overrides->policyfile_set == 0) ? ps->policyfile : overrides->policyfile; return ps; } static const char *set_adobe_crossdomainpolicy_enabled(cmd_parms *parms, void *dummy, int flag) { adobe_crossdomainpolicy_module_config_t *conf; const char *err = ap_check_cmd_context(parms, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); if (err) { return err; } conf = (adobe_crossdomainpolicy_module_config_t *)ap_get_module_config(parms->server->module_config, &adobe_crossdomainpolicy_module); conf->enabled = flag; conf->enabled_set = 1; return NULL; } static const char *set_adobe_crossdomainpolicy_file(cmd_parms *parms, void *dummy, const char *arg) { adobe_crossdomainpolicy_module_config_t *conf; apr_finfo_t finfo; const char *err = ap_check_cmd_context(parms, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); if (err) { return err; } conf = (adobe_crossdomainpolicy_module_config_t *)ap_get_module_config(parms->server->module_config, &adobe_crossdomainpolicy_module); // First STAT the file! if (apr_stat(&finfo, arg, APR_FINFO_SIZE, parms->pool) != APR_SUCCESS) { return apr_pstrcat(parms->pool, "Policy file does not exist: ", arg, NULL); } conf->policyfile_set = 1; conf->policyfile = apr_pstrdup(parms->pool, arg); return NULL; } static const command_rec adobe_crossdomainpolicy_cmds[] = { AP_INIT_FLAG("AdobePolicyFileServerEnabled", set_adobe_crossdomainpolicy_enabled, NULL, RSRC_CONF, "Enable the Abobe Policy File Server on this VirtualHost."), AP_INIT_TAKE1("AdobePolicyFile", set_adobe_crossdomainpolicy_file, NULL, RSRC_CONF, "Specify the path to the Adobe policy file to serve for this VirtualHost"), {NULL} }; static void adobe_crossdomainpolicy_register_hooks(apr_pool_t *p) { ap_hook_process_connection(process_connection, NULL, NULL, APR_HOOK_FIRST); } /* Dispatch list for API hooks */ module AP_MODULE_DECLARE_DATA adobe_crossdomainpolicy_module = { STANDARD20_MODULE_STUFF, NULL, /* create per-dir config structures */ NULL, /* merge per-dir config structures */ create_adobe_crossdomainpolicy_config, /* create per-server config structures */ merge_adobe_crossdomainpolicy_config, /* merge per-server config structures */ adobe_crossdomainpolicy_cmds, /* table of config file commands */ adobe_crossdomainpolicy_register_hooks /* register hooks */ };