diff options
Diffstat (limited to 'alarm/node_modules/node-forge/mod_fsp')
-rw-r--r-- | alarm/node_modules/node-forge/mod_fsp/README | 135 | ||||
-rw-r--r-- | alarm/node_modules/node-forge/mod_fsp/mod_fsp.c | 415 |
2 files changed, 550 insertions, 0 deletions
diff --git a/alarm/node_modules/node-forge/mod_fsp/README b/alarm/node_modules/node-forge/mod_fsp/README new file mode 100644 index 0000000..0331e01 --- /dev/null +++ b/alarm/node_modules/node-forge/mod_fsp/README @@ -0,0 +1,135 @@ +======= +mod_fsp +======= + +mod_fsp is an Apache2 module for providing a Flash Socket Policy on the +same port that HTTP is served. The cross-domain policy that is served is +specified via a configuration option 'FSPPolicyFile'. + +If a flash application sends a policy file request to an Apache server +that has enabled and configured the mod_fsp module over its HTTP port, +then the configured cross-domain policy will be returned as the response. + +======== +Building +======== + +To build the mod_fsp source code you can use Apache2's module +build and installation tool: 'apxs2' which is, at the time of +this writing, available on debian in the package: + +apache2-threaded-dev + +To compile mod_fsp you would run the following command: + +apxs2 -c mod_fsp.c + +============ +Installation +============ + +To install mod_fsp you the following command as root: + +apxs2 -c -i -a mod_fsp.c + +You must then restart your apache2 process, typically like so: + +/etc/init.d/apache2 restart + +=================== +Manual Installation +=================== + +To manually enable mod_dsp on your Apache2 server, you must copy the +module file to the appropriate directory and create a load file. + +The module file: + +fsp.so (The library extension may vary if you are not using linux). + +Must be copied to Apache's module installation directory which is +typically located (on a debian system): + +/usr/lib/apache2/modules + +The load file: + +fsp.load + +Must be created in Apache2's 'mods-available' directory, typically +located (on a debian system): + +/etc/apache2/mods-available + +The load file should contain: + +LoadModule fsp_module /usr/lib/apache2/modules/mod_fsp.so + +If your Apache module installation directory is different from +the one listed above, you will need to set the correct one in the +fsp.load file. + +To actually enable the module you must create a symbolic link in +Apache's 'mods-enabled' directory, typically located (on debian): + +/etc/apache2/mods-enabled + +By typing (from that directory): + +ln -s ../mods-available/fsp.load fsp.load + +============= +Configuration +============= + +Once mod_fsp is installed, it must be configured. There is currently +only one configuration option for mod_fsp: 'FSPPolicyFile'. This +configuration option will set the file that mod_fsp will look in +on apache startup for the cross-domain policy to serve. This option +can be provided on a per-port basis. Each port can use a different +one, but VirtualServers on a single port will use the same one. This +is a limitation of the design by Adobe. + +Note: The cross-domain policy may fail to be served if the configuration +option isn't added in the first VirtualHost entry (for a given port) read +by Apache. + +An example of this configuration in use: + +<VirtualHost *:80> + ServerName example.com + DocumentRoot /var/www/example.com + ErrorLog /var/log/apache2/example.com-error.log + CustomLog /var/log/apache2/example.com-access.log vhost_combined + + # mod_fsp config option + FSPPolicyFile /etc/apache2/crossdomain/crossdomain.xml + + <Directory /var/www/example.com> + Options Indexes FollowSymLinks MultiViews + AllowOverride All + Order allow,deny + allow from all + </Directory> + +</VirtualHost> + +And example of the most permissive cross-domain policy file for flash: + +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE cross-domain-policy SYSTEM +"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"> +<cross-domain-policy> +<site-control permitted-cross-domain-policies="all"/> +<allow-access-from domain="*" to-ports="*"/> +<allow-http-request-headers-from domain="*" headers="*"/> +</cross-domain-policy> + +================== +Note about SSL/TLS +================== + +Flash currently has no built-in SSL/TLS support so there is no +reason to specify an 'FSPPolicyFile' option for SSL servers. The +Flash player cannot directly communicate with them when doing +internal look ups of policy files. diff --git a/alarm/node_modules/node-forge/mod_fsp/mod_fsp.c b/alarm/node_modules/node-forge/mod_fsp/mod_fsp.c new file mode 100644 index 0000000..8beb824 --- /dev/null +++ b/alarm/node_modules/node-forge/mod_fsp/mod_fsp.c @@ -0,0 +1,415 @@ +/** + * Flash Socket Policy Apache Module. + * + * This module provides a flash socket policy file on the same port that + * serves HTTP on Apache. This can help simplify setting up a server that + * supports cross-domain communication with flash. + * + * Quick note about Apache memory handling: Data is allocated from pools and + * is not manually returned to those pools. The pools are typically considered + * short-lived and will be cleaned up automatically by Apache. + * + * @author Dave Longley + * + * Copyright (c) 2010 Digital Bazaar, Inc. All rights reserved. + */ +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" + +#include "ap_compat.h" + +#include <string.h> + +// length of a policy file request +#define PFR_LENGTH 23 + +// declare main module +module AP_MODULE_DECLARE_DATA fsp_module; + +// configuration for the module +typedef struct fsp_config +{ + // the cross-domain policy to serve + char* policy; + apr_size_t policy_length; +} fsp_config; + +// filter state for keeping track of detected policy file requests +typedef struct filter_state +{ + fsp_config* cfg; + int checked; + int found; +} filter_state; + +// for registering hooks, filters, etc. +static void fsp_register_hooks(apr_pool_t *p); +static int fsp_pre_connection(conn_rec *c, void *csd); + +// filter handler declarations +static apr_status_t fsp_input_filter( + ap_filter_t* f, apr_bucket_brigade* bb, + ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes); +static int fsp_output_filter(ap_filter_t* f, apr_bucket_brigade* bb); + +/** + * Registers the hooks for this module. + * + * @param p the pool to allocate from, if necessary. + */ +static void fsp_register_hooks(apr_pool_t* p) +{ + // registers the pre-connection hook to handle adding filters + ap_hook_pre_connection( + fsp_pre_connection, NULL, NULL, APR_HOOK_MIDDLE); + + // will parse a policy file request, to be added in pre_connection + ap_register_input_filter( + "fsp_request", fsp_input_filter, + NULL, AP_FTYPE_CONNECTION); + + // will emit a cross-domain policy response to be added in pre_connection + ap_register_output_filter( + "fsp_response", fsp_output_filter, + NULL, AP_FTYPE_CONNECTION); +} + +/** + * A hook that is called before a connection is handled. This function will + * get the module configuration and add the flash socket policy filters if + * a cross-domain policy has been specified in the configuration. + * + * @param c the connection. + * @param csd the connection socket descriptor. + * + * @return OK on success. + */ +static int fsp_pre_connection(conn_rec* c, void* csd) +{ + // only install filters if a policy was specified in the module config + fsp_config* cfg = ap_get_module_config( + c->base_server->module_config, &fsp_module); + if(cfg->policy != NULL) + { + // allocate filter state + filter_state* state = apr_palloc(c->pool, sizeof(filter_state)); + if(state != NULL) + { + // initialize state + state->cfg = cfg; + state->checked = state->found = 0; + + // add filters + ap_add_input_filter("fsp_request", state, NULL, c); + ap_add_output_filter("fsp_response", state, NULL, c); + } + } + + return OK; +} + +/** + * Searches the input request for a flash socket policy request. This request, + * unfortunately, does not follow the HTTP protocol and cannot be handled + * via a special HTTP handler. Instead, it is a short xml string followed by + * a null character: + * + * '<policy-file-request/>\0' + * + * A peek into the incoming data checks the first character of the stream to + * see if it is '<' (as opposed to typically something else for HTTP). If it + * is not, then this function returns and HTTP input is read normally. If it + * is, then the remaining bytes in the policy-file-request are read and + * checked. If a match is found, then the filter state will be updated to + * inform the output filter to send a cross-domain policy as a response. If + * no match is found, HTTP traffic will proceed as usual. + * + * @param f the input filter. + * @param state the filter state. + * + * @return APR_SUCCESS on success, some other status on failure. + */ +static apr_status_t find_policy_file_request( + ap_filter_t* f, filter_state* state) +{ + apr_status_t rval = APR_SUCCESS; + + // create a temp buffer for speculative reads + apr_bucket_brigade* tmp = apr_brigade_create(f->c->pool, f->c->bucket_alloc); + + // FIXME: not sure how blocking mode works ... can it return fewer than + // the number of specified bytes? + + // peek at the first PFR_LENGTH bytes + rval = ap_get_brigade( + f->next, tmp, AP_MODE_SPECULATIVE, APR_BLOCK_READ, PFR_LENGTH); + if(rval == APR_SUCCESS) + { + // quickly check the first bucket for the beginning of a pfr + const char* data; + apr_size_t length; + apr_bucket* b = APR_BRIGADE_FIRST(tmp); + rval = apr_bucket_read(b, &data, &length, APR_BLOCK_READ); + if(rval == APR_SUCCESS && length > 0 && data[0] == '<') + { + // possible policy file request, fill local buffer + char pfr[PFR_LENGTH]; + char* ptr = pfr; + memcpy(ptr, data, length); + ptr += length; + memset(ptr, '\0', PFR_LENGTH - length); + b = APR_BUCKET_NEXT(b); + while(rval == APR_SUCCESS && b != APR_BRIGADE_SENTINEL(tmp)) + { + rval = apr_bucket_read(b, &data, &length, APR_BLOCK_READ); + if(rval == APR_SUCCESS) + { + memcpy(ptr, data, length); + ptr += length; + b = APR_BUCKET_NEXT(b); + } + } + + if(rval == APR_SUCCESS) + { + // see if pfr is a policy file request: '<policy-file-request/>\0' + if((ptr - pfr == PFR_LENGTH) && (pfr[PFR_LENGTH - 1] == '\0') && + (strncmp(pfr, "<policy-file-request/>", PFR_LENGTH -1) == 0)) + { + // pfr found + state->found = 1; + } + } + } + } + + return rval; +} + +/** + * Handles incoming data. If an attempt has not yet been made to look for + * a policy request (it is the beginning of the connection), then one is + * made. Otherwise this filter does nothing. + * + * If an attempt is made to find a policy request and one is not found, then + * reads proceed as normal. If one is found, then the filter state is modified + * to inform the output filter to send a policy request and the return value + * of this filter is EOF indicating that the connection should close after + * sending the cross-domain policy. + * + * @param f the input filter. + * @param bb the brigate to fill with input from the next filters in the chain + * and then process (look for a policy file request). + * @param mode the type of read requested (ie: AP_MODE_GETLINE means read until + * a CRLF is found, AP_MODE_GETBYTES means 'nbytes' of data, etc). + * @param block APR_BLOCK_READ or APR_NONBLOCK_READ, indicates the type of + * blocking to do when trying to read. + * @param nbytes used if the read mode is appropriate to specify the number of + * bytes to read (set to 0 for AP_MODE_GETLINE). + * + * @return the status of the input (ie: APR_SUCCESS for read success, APR_EOF + * for end of stream, APR_EAGAIN to read again when non-blocking). + */ +static apr_status_t fsp_input_filter( + ap_filter_t* f, apr_bucket_brigade* bb, + ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes) +{ + apr_status_t rval = APR_SUCCESS; + + filter_state* state = f->ctx; + if(state->checked == 1) + { + // already checked for policy file request, just read from other filters + rval = ap_get_brigade(f->next, bb, mode, block, nbytes); + } + else + { + // try to find a policy file request + rval = find_policy_file_request(f, state); + state->checked = 1; + + if(rval == APR_SUCCESS) + { + if(state->found) + { + // do read of PFR_LENGTH bytes, consider end of stream + rval = ap_get_brigade( + f->next, bb, AP_MODE_READBYTES, APR_BLOCK_READ, PFR_LENGTH); + rval = APR_EOF; + } + else + { + // do normal read + rval = ap_get_brigade(f->next, bb, mode, block, nbytes); + } + } + } + + return rval; +} + +/** + * Handles outgoing data. If the filter state indicates that a cross-domain + * policy should be sent then it is added to the outgoing brigade of data. If + * a policy request was not detected, then this filter makes no changes to + * the outgoing data. + * + * @param f the output filter. + * @param bb the outgoing brigade of data. + * + * @return APR_SUCCESS on success, some other status on error. + */ +static int fsp_output_filter(ap_filter_t* f, apr_bucket_brigade* bb) +{ + apr_status_t rval = APR_SUCCESS; + + filter_state* state = f->ctx; + if(state->found) + { + // found policy-file-request, add response bucket + // bucket is immortal because the data is stored in the configuration + // and doesn't need to be copied + apr_bucket* head = apr_bucket_immortal_create( + state->cfg->policy, state->cfg->policy_length, bb->bucket_alloc); + APR_BRIGADE_INSERT_HEAD(bb, head); + } + + if(rval == APR_SUCCESS) + { + // pass brigade to next filter + rval = ap_pass_brigade(f->next, bb); + } + + return rval; +} + +/** + * Creates the configuration for this module. + * + * @param p the pool to allocate from. + * @param s the server the configuration is for. + * + * @return the configuration data. + */ +static void* fsp_create_config(apr_pool_t* p, server_rec* s) +{ + // allocate config + fsp_config* cfg = apr_palloc(p, sizeof(fsp_config)); + + // no default policy + cfg->policy = NULL; + cfg->policy_length = 0; + return cfg; +} + +/** + * Sets the policy file to use from the configuration. + * + * @param parms the command directive parameters. + * @param userdata NULL, not used. + * @param arg the string argument to the command directive (the file with + * the cross-domain policy to serve as content). + * + * @return NULL on success, otherwise an error string to display. + */ +static const char* fsp_set_policy_file( + cmd_parms* parms, void* userdata, const char* arg) +{ + const char* rval = NULL; + + apr_pool_t* pool = (apr_pool_t*)parms->pool; + fsp_config* cfg = ap_get_module_config( + parms->server->module_config, &fsp_module); + + // ensure command is in the correct context + rval = ap_check_cmd_context(parms, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); + if(rval == NULL) + { + // get canonical file name + char* fname = ap_server_root_relative(pool, arg); + if(fname == NULL) + { + rval = (const char*)apr_psprintf( + pool, "%s: Invalid policy file '%s'", + parms->cmd->name, arg); + } + else + { + // try to open the file + apr_status_t rv; + apr_file_t* fd; + apr_finfo_t finfo; + rv = apr_file_open(&fd, fname, APR_READ, APR_OS_DEFAULT, pool); + if(rv == APR_SUCCESS) + { + // stat file + rv = apr_file_info_get(&finfo, APR_FINFO_NORM, fd); + if(rv == APR_SUCCESS) + { + // ensure file is not empty + apr_size_t length = (apr_size_t)finfo.size; + if(length <= 0) + { + rval = (const char*)apr_psprintf( + pool, "%s: policy file '%s' is empty", + parms->cmd->name, fname); + } + // read file + else + { + char* buf = (char*)apr_palloc(pool, length + 1); + buf[length] = '\0'; + rv = apr_file_read_full(fd, buf, length, NULL); + if(rv == APR_SUCCESS) + { + // TODO: validate file + // save policy string + cfg->policy = buf; + cfg->policy_length = length + 1; + } + } + + // close the file + apr_file_close(fd); + } + } + + // handle error case + if(rv != APR_SUCCESS) + { + char errmsg[120]; + rval = (const char*)apr_psprintf( + pool, "%s: Invalid policy file '%s' (%s)", + parms->cmd->name, fname, + apr_strerror(rv, errmsg, sizeof(errmsg))); + } + } + } + + return rval; +} + +// table of configuration directives +static const command_rec fsp_cmds[] = +{ + AP_INIT_TAKE1( + "FSPPolicyFile", /* the directive */ + fsp_set_policy_file, /* function to call when directive is found */ + NULL, /* user data to pass to function, not used */ + RSRC_CONF, /* indicates the directive appears outside of <Location> */ + "FSPPolicyFile (string) The cross-domain policy file to use"), /* docs */ + {NULL} +}; + +// module setup +module AP_MODULE_DECLARE_DATA fsp_module = +{ + STANDARD20_MODULE_STUFF, /* stuff declared in every 2.0 mod */ + NULL, /* create per-directory config structure */ + NULL, /* merge per-directory config structures */ + fsp_create_config, /* create per-server config structure */ + NULL, /* merge per-server config structures */ + fsp_cmds, /* command apr_table_t */ + fsp_register_hooks /* register hooks */ +}; |