Beispiel #1
0
/*
 * check if the provided OAuth/OIDC response type is supported
 */
const char *oidc_valid_response_type(apr_pool_t *pool, const char *arg) {
	if (oidc_proto_flow_is_supported(pool, arg) == FALSE) {
		return apr_psprintf(pool,
				"oidc_valid_response_type: type must be one of %s",
				apr_array_pstrcat(pool, oidc_proto_supported_flows(pool), '|'));
	}
	return NULL;
}
Beispiel #2
0
/*
 * check if the provided JWT encryption cipher is supported
 */
const char *oidc_valid_encrypted_response_enc(apr_pool_t *pool, const char *arg) {
	if (oidc_jose_jwe_encryption_is_supported(pool, arg) == FALSE) {
		return apr_psprintf(pool,
				"unsupported/invalid encryption type '%s'; must be one of [%s]",
				arg,
				apr_array_pstrcat(pool,
						oidc_jose_jwe_supported_encryptions(pool), '|'));
	}
	return NULL;
}
Beispiel #3
0
/*
 * check if the provided JWT signature algorithm is supported
 */
const char *oidc_valid_signed_response_alg(apr_pool_t *pool, const char *arg) {
	if (oidc_jose_jws_algorithm_is_supported(pool, arg) == FALSE) {
		return apr_psprintf(pool,
				"unsupported/invalid signing algorithm '%s'; must be one of [%s]",
				arg,
				apr_array_pstrcat(pool,
						oidc_jose_jws_supported_algorithms(pool), '|'));
	}
	return NULL;
}
Beispiel #4
0
int ml_list_provider(lua_State*L)
{
  const request_rec* r = CHECK_REQUEST_OBJECT(1);
  const char*group = luaL_checkstring(L, 2);
  const char*version = luaL_optstring(L, 3, "0");
  apr_array_header_t* arr = ap_list_provider_names(r->pool, group, version);

  lua_pushstring(L, apr_array_pstrcat(r->pool, arr, ','));
  return 1;
}
Beispiel #5
0
// This is the method which does all the work handling the uploads.  It's only
// triggered by the fixup filter if +porter_should_rewrite_body+ returns true.
apr_status_t porter_process_upload(request_rec *r)
{
  porter_server_conf *config = (porter_server_conf *) ap_get_module_config(r->server->module_config, &porter_module);

  // Prepare the apreq objects.
  apreq_handle_t *req = apreq_handle_apache2(r);
  const apr_table_t *request_body = apreq_params(req, r->pool);

  // Create our upload request object, this is fleshed out by the rest of this method
  porter_upload_request_t *upload_request = porter_create_request(req, r, config);

  // This happens with malformed requests.  apreq_params should never return null
  // when the content-length is > 0 and it's a multipart request.  So just assume
  // it's broken and return bad request.  Otherwise subsequent method calls will
  // cause a segfault
  if (request_body == NULL)
  {
    PORTER_LOG_REQUEST_ERROR("Invalid request body");
    return HTTP_BAD_REQUEST;
  }

  // loop over each parameter provided by the user (see porter_each_parameter)
  apr_table_do(porter_each_parameter, upload_request, request_body, NULL);

  // If any of the parameter handlers return an error, they save the error code
  // in the upload_request.  So return that same error code.
  if (upload_request->status != APR_SUCCESS)
  {
    return upload_request->status;
  }


  // Just because the content type is multipart and the content-length was > 0 doesn't
  // mean that the user actually uploaded any files.  If they didn't, just return success
  // and let the original body be passed upstream.
  if (!apr_is_empty_array(upload_request->param_names))
  {
    // Write the parameter names to the X-Uploads header (comma seperated)
    const char *upload_parameters = apr_array_pstrcat(r->pool, upload_request->param_names, ',');
    apr_off_t len;
    apr_table_setn(r->headers_in, HTTP_X_UPLOADS, upload_parameters);

    // figure out the length of the newly rewritten body and set it in the request
    // along with the right content type.
    apr_brigade_length(upload_request->bucket_brigade, 0, &len);
    apr_table_setn(r->headers_in, "Content-Length", apr_itoa(r->pool, len));
    apr_table_setn(r->headers_in, "Content-Type", "application/x-www-form-urlencoded");

    // Add our input filter to the filter chain, this allows
    // us to replace the request body with our own one, and ensure that
    // gets passed down to the handler.
    ap_add_input_filter_handle(porter_input_filter_handle, upload_request, r, r->connection);
  }
  return APR_SUCCESS;
}
Beispiel #6
0
apr_status_t exec_self( int argc,
                        const char *argv[] )
{
    apr_status_t rv = APR_SUCCESS;
    apr_array_header_t *dpaths =
        get_property_array( "hashdot.vm.libpath" );

    if( dpaths == NULL ) return rv;

    char * ldpenv = NULL;
    apr_env_get( &ldpenv, LIB_PATH_VAR, _mp );

    apr_array_header_t *newpaths =
        apr_array_make( _mp, 8, sizeof( const char* ) );
    int i;
    for( i = 0; i < dpaths->nelts; i++ ) {
        const char *path = ((const char **) dpaths->elts )[i];
        if( !ldpenv || !strstr( ldpenv, path ) ) {
            *( (const char **) apr_array_push( newpaths ) ) = path;
            DEBUG( "New path to add: %s", path );
        }
    }

    // Need to set LD_LIBRARY_PATH, new paths found.
    if( newpaths->nelts > 0 ) {
        if( ldpenv ) {
            *( (const char **) apr_array_push( newpaths ) ) = ldpenv;
        }
        ldpenv = apr_array_pstrcat( _mp, newpaths, ':' );
        DEBUG( "New %s = [%s]", LIB_PATH_VAR, ldpenv );
        rv = apr_env_set( LIB_PATH_VAR, ldpenv, _mp );

        const char *exe_name = NULL;
        if( rv == APR_SUCCESS ) {
            rv = find_self_exe( &exe_name );
        }

        // Exec using linux(-only?) /proc/self/exe link to self,
        // instead of argv[0], since the later will not specify a path
        // when initial call is made via PATH, and since execve won't
        // itself look at PATH.
        // Note: Can't use apr_proc_create for this, since it always
        // forks first.

        if( rv == APR_SUCCESS ) {
            DEBUG( "Exec'ing self as %s", argv[0] );
            execv( exe_name, (char * const *) argv );
            rv = APR_FROM_OS_ERROR( errno ); //shouldn't return from execv call
        }
    }

    return rv;
}
Beispiel #7
0
/**
 * field -> "path" or "cpath"
 * sub_pat -> "?.lua"
 * rep_pat -> "./?.lua"
 * pool -> lifecycle pool for allocations
 * paths -> things to add
 * file -> ???
 */
static void munge_path(lua_State *L,
                       const char *field,
                       const char *sub_pat,
                       const char *rep_pat,
                       apr_pool_t *pool,
                       apr_array_header_t *paths,
                       const char *file)
{
    const char *current;
    const char *parent_dir;
    const char *pattern;
    const char *modified;
    char *part;

    lua_getglobal(L, "package");
    lua_getfield(L, -1, field);
    
    current = lua_tostring(L, -1);

    parent_dir = ap_make_dirstr_parent(pool, file);
 
    pattern = apr_pstrcat(pool, parent_dir, sub_pat, NULL);

    luaL_gsub(L, current, rep_pat, pattern);
    lua_setfield(L, -3, field);
    lua_getfield(L, -2, field);
    modified = lua_tostring(L, -1);


    lua_pop(L, 2);

    part = apr_pstrcat(pool, modified, ";", apr_array_pstrcat(pool, paths, ';'),
                       NULL);

    lua_pushstring(L, part);
    lua_setfield(L, -2, field);
    lua_pop(L, 1);              /* pop "package" off the stack     */
}
Beispiel #8
0
static int check_speling(request_rec *r)
{
    spconfig *cfg;
    char *good, *bad, *postgood, *url;
    apr_finfo_t dirent;
    int filoc, dotloc, urlen, pglen;
    apr_array_header_t *candidates = NULL;
    apr_dir_t          *dir;

    cfg = ap_get_module_config(r->per_dir_config, &speling_module);
    if (!cfg->enabled) {
        return DECLINED;
    }

    /* We only want to worry about GETs */
    if (r->method_number != M_GET) {
        return DECLINED;
    }

    /* We've already got a file of some kind or another */
    if (r->finfo.filetype != APR_NOFILE) {
        return DECLINED;
    }

    /* Not a file request */
    if (r->proxyreq || !r->filename) {
        return DECLINED;
    }

    /* This is a sub request - don't mess with it */
    if (r->main) {
        return DECLINED;
    }

    /*
     * The request should end up looking like this:
     * r->uri: /correct-url/mispelling/more
     * r->filename: /correct-file/mispelling r->path_info: /more
     *
     * So we do this in steps. First break r->filename into two pieces
     */

    filoc = ap_rind(r->filename, '/');
    /*
     * Don't do anything if the request doesn't contain a slash, or
     * requests "/"
     */
    if (filoc == -1 || strcmp(r->uri, "/") == 0) {
        return DECLINED;
    }

    /* good = /correct-file */
    good = apr_pstrndup(r->pool, r->filename, filoc);
    /* bad = mispelling */
    bad = apr_pstrdup(r->pool, r->filename + filoc + 1);
    /* postgood = mispelling/more */
    postgood = apr_pstrcat(r->pool, bad, r->path_info, NULL);

    urlen = strlen(r->uri);
    pglen = strlen(postgood);

    /* Check to see if the URL pieces add up */
    if (strcmp(postgood, r->uri + (urlen - pglen))) {
        return DECLINED;
    }

    /* url = /correct-url */
    url = apr_pstrndup(r->pool, r->uri, (urlen - pglen));

    /* Now open the directory and do ourselves a check... */
    if (apr_dir_open(&dir, good, r->pool) != APR_SUCCESS) {
        /* Oops, not a directory... */
        return DECLINED;
    }

    candidates = apr_array_make(r->pool, 2, sizeof(misspelled_file));

    dotloc = ap_ind(bad, '.');
    if (dotloc == -1) {
        dotloc = strlen(bad);
    }

    while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dir) == APR_SUCCESS) {
        sp_reason q;

        /*
         * If we end up with a "fixed" URL which is identical to the
         * requested one, we must have found a broken symlink or some such.
         * Do _not_ try to redirect this, it causes a loop!
         */
        if (strcmp(bad, dirent.name) == 0) {
            apr_dir_close(dir);
            return OK;
        }

        /*
         * miscapitalization errors are checked first (like, e.g., lower case
         * file, upper case request)
         */
        else if (strcasecmp(bad, dirent.name) == 0) {
            misspelled_file *sp_new;

            sp_new = (misspelled_file *) apr_array_push(candidates);
            sp_new->name = apr_pstrdup(r->pool, dirent.name);
            sp_new->quality = SP_MISCAPITALIZED;
        }

        /*
         * simple typing errors are checked next (like, e.g.,
         * missing/extra/transposed char)
         */
        else if ((cfg->check_case_only == 0)
                 && ((q = spdist(bad, dirent.name)) != SP_VERYDIFFERENT)) {
            misspelled_file *sp_new;

            sp_new = (misspelled_file *) apr_array_push(candidates);
            sp_new->name = apr_pstrdup(r->pool, dirent.name);
            sp_new->quality = q;
        }

        /*
         * The spdist() should have found the majority of the misspelled
         * requests.  It is of questionable use to continue looking for
         * files with the same base name, but potentially of totally wrong
         * type (index.html <-> index.db).
         *
         * If you're using MultiViews, and have a file named foobar.html,
         * which you refer to as "foobar", and someone tried to access
         * "Foobar", without CheckBasenameMatch, mod_speling won't find it,
         * because it won't find anything matching that spelling.
         * With the extension-munging, it would locate "foobar.html".
         */
        else if ((cfg->check_case_only == 0) &&
                 (cfg->check_basename_match == 1)) {
            /*
             * Okay... we didn't find anything. Now we take out the hard-core
             * power tools. There are several cases here. Someone might have
             * entered a wrong extension (.htm instead of .html or vice
             * versa) or the document could be negotiated. At any rate, now
             * we just compare stuff before the first dot. If it matches, we
             * figure we got us a match. This can result in wrong things if
             * there are files of different content types but the same prefix
             * (e.g. foo.gif and foo.html) This code will pick the first one
             * it finds. Better than a Not Found, though.
             */
            int entloc = ap_ind(dirent.name, '.');
            if (entloc == -1) {
                entloc = strlen(dirent.name);
            }

            if ((dotloc == entloc)
                && !strncasecmp(bad, dirent.name, dotloc)) {
                misspelled_file *sp_new;

                sp_new = (misspelled_file *) apr_array_push(candidates);
                sp_new->name = apr_pstrdup(r->pool, dirent.name);
                sp_new->quality = SP_VERYDIFFERENT;
            }
        }
    }
    apr_dir_close(dir);

    if (candidates->nelts != 0) {
        /* Wow... we found us a mispelling. Construct a fixed url */
        char *nuri;
        const char *ref;
        misspelled_file *variant = (misspelled_file *) candidates->elts;
        int i;

        ref = apr_table_get(r->headers_in, "Referer");

        qsort((void *) candidates->elts, candidates->nelts,
              sizeof(misspelled_file), sort_by_quality);

        /*
         * Conditions for immediate redirection:
         *     a) the first candidate was not found by stripping the suffix
         * AND b) there exists only one candidate OR the best match is not
         *        ambiguous
         * then return a redirection right away.
         */
        if (variant[0].quality != SP_VERYDIFFERENT
            && (candidates->nelts == 1
                || variant[0].quality != variant[1].quality)) {

            nuri = ap_escape_uri(r->pool, apr_pstrcat(r->pool, url,
                                                     variant[0].name,
                                                     r->path_info, NULL));
            if (r->parsed_uri.query)
                nuri = apr_pstrcat(r->pool, nuri, "?", r->parsed_uri.query, NULL);

            apr_table_setn(r->headers_out, "Location",
                          ap_construct_url(r->pool, nuri, r));

            ap_log_rerror(APLOG_MARK, APLOG_INFO, APR_SUCCESS,
                          r,
                          ref ? "Fixed spelling: %s to %s from %s"
                              : "Fixed spelling: %s to %s%s",
                          r->uri, nuri,
                          (ref ? ref : ""));

            return HTTP_MOVED_PERMANENTLY;
        }
        /*
         * Otherwise, a "[300] Multiple Choices" list with the variants is
         * returned.
         */
        else {
            apr_pool_t *p;
            apr_table_t *notes;
            apr_pool_t *sub_pool;
            apr_array_header_t *t;
            apr_array_header_t *v;


            if (r->main == NULL) {
                p = r->pool;
                notes = r->notes;
            }
            else {
                p = r->main->pool;
                notes = r->main->notes;
            }

            if (apr_pool_create(&sub_pool, p) != APR_SUCCESS)
                return DECLINED;

            t = apr_array_make(sub_pool, candidates->nelts * 8 + 8,
                              sizeof(char *));
            v = apr_array_make(sub_pool, candidates->nelts * 5,
                              sizeof(char *));

            /* Generate the response text. */

            *(const char **)apr_array_push(t) =
                          "The document name you requested (<code>";
            *(const char **)apr_array_push(t) = ap_escape_html(sub_pool, r->uri);
            *(const char **)apr_array_push(t) =
                           "</code>) could not be found on this server.\n"
                           "However, we found documents with names similar "
                           "to the one you requested.<p>"
                           "Available documents:\n<ul>\n";

            for (i = 0; i < candidates->nelts; ++i) {
                char *vuri;
                const char *reason;

                reason = sp_reason_str[(int) (variant[i].quality)];
                /* The format isn't very neat... */
                vuri = apr_pstrcat(sub_pool, url, variant[i].name, r->path_info,
                                  (r->parsed_uri.query != NULL) ? "?" : "",
                                  (r->parsed_uri.query != NULL)
                                      ? r->parsed_uri.query : "",
                                  NULL);
                *(const char **)apr_array_push(v) = "\"";
                *(const char **)apr_array_push(v) = ap_escape_uri(sub_pool, vuri);
                *(const char **)apr_array_push(v) = "\";\"";
                *(const char **)apr_array_push(v) = reason;
                *(const char **)apr_array_push(v) = "\"";

                *(const char **)apr_array_push(t) = "<li><a href=\"";
                *(const char **)apr_array_push(t) = ap_escape_uri(sub_pool, vuri);
                *(const char **)apr_array_push(t) = "\">";
                *(const char **)apr_array_push(t) = ap_escape_html(sub_pool, vuri);
                *(const char **)apr_array_push(t) = "</a> (";
                *(const char **)apr_array_push(t) = reason;
                *(const char **)apr_array_push(t) = ")\n";

                /*
                 * when we have printed the "close matches" and there are
                 * more "distant matches" (matched by stripping the suffix),
                 * then we insert an additional separator text to suggest
                 * that the user LOOK CLOSELY whether these are really the
                 * files she wanted.
                 */
                if (i > 0 && i < candidates->nelts - 1
                    && variant[i].quality != SP_VERYDIFFERENT
                    && variant[i + 1].quality == SP_VERYDIFFERENT) {
                    *(const char **)apr_array_push(t) =
                                   "</ul>\nFurthermore, the following related "
                                   "documents were found:\n<ul>\n";
                }
            }
            *(const char **)apr_array_push(t) = "</ul>\n";

            /* If we know there was a referring page, add a note: */
            if (ref != NULL) {
                *(const char **)apr_array_push(t) =
                               "Please consider informing the owner of the "
                               "<a href=\"";
                *(const char **)apr_array_push(t) = ap_escape_uri(sub_pool, ref);
                *(const char **)apr_array_push(t) = "\">referring page</a> "
                               "about the broken link.\n";
            }


            /* Pass our apr_table_t to http_protocol.c (see mod_negotiation): */
            apr_table_setn(notes, "variant-list", apr_array_pstrcat(p, t, 0));

            apr_table_mergen(r->subprocess_env, "VARIANTS",
                            apr_array_pstrcat(p, v, ','));

            apr_pool_destroy(sub_pool);

            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
                         ref ? "Spelling fix: %s: %d candidates from %s"
                             : "Spelling fix: %s: %d candidates%s",
                         r->uri, candidates->nelts,
                         (ref ? ref : ""));

            return HTTP_MULTIPLE_CHOICES;
        }
    }

    return OK;
}
Beispiel #9
0
/* this is where the magic happens */
static set* _cluster_keys(range_request* rr, apr_pool_t* pool,
                          const char* cluster, const char* cluster_file)
{
    apr_array_header_t* working_range;
    set* sections;
    char* section;
    char* cur_section;
    apr_pool_t* req_pool = range_request_pool(rr);
    yaml_node_t *node;
    yaml_node_t *rootnode;
    yaml_node_t *keynode;
    yaml_node_t *valuenode;
    yaml_parser_t parser;
    yaml_node_item_t *item;
    yaml_node_pair_t *pair;
    
    yaml_document_t document;
    
    FILE* fp = fopen(cluster_file, "r");

    /* make sure we can open the file and parse it */
    if (!fp) {
        range_request_warn(rr, "%s: %s not readable", cluster, cluster_file);
        return set_new(pool, 0);
    }

    if (!yaml_parser_initialize(&parser)) {
        range_request_warn(rr, "%s: cannot initialize yaml parser", cluster);
        fclose(fp);
        return set_new(pool, 0);
    }

    yaml_parser_set_input_file(&parser, fp);
    if(!yaml_parser_load(&parser, &document)) {
        range_request_warn(rr, "%s: malformatted cluster definition %s",
                           cluster, cluster_file);
        fclose(fp);
        yaml_parser_delete(&parser);
        return set_new(pool, 0);
    }
    fclose(fp);
    
    rootnode = yaml_document_get_root_node(&document);
    /* make sure it's just a simple dictionary */
    if(rootnode->type != YAML_MAPPING_NODE) {
        range_request_warn(rr, "%s: malformatted cluster definition %s",
                           cluster, cluster_file);
        yaml_document_delete(&document);
        yaml_parser_delete(&parser);
        return set_new(pool, 0);
    }

    /* "sections" refers to cluster sections - %cluster:SECTION
       it's what we're going to return */
    sections = set_new(pool, 0);
    section = cur_section = NULL;

    for(pair = rootnode->data.mapping.pairs.start;
        pair < rootnode->data.mapping.pairs.top;
        pair++) { /* these are the keys */
        keynode = yaml_document_get_node(&document, pair->key);
        /* cur_section is the keyname - the WHATEVER in %cluster:WHATEVER */
        cur_section = apr_pstrdup(pool, (char *)(keynode->data.scalar.value));
        valuenode = yaml_document_get_node(&document, pair->value);
        /* if the value is a scalar, that's our answer */
        if(valuenode->type == YAML_SCALAR_NODE) {
            set_add(sections, cur_section,
                    apr_psprintf(pool, "%s", valuenode->data.scalar.value));
        } else if (valuenode->type == YAML_SEQUENCE_NODE) {
            /* otherwise, glue together all the values in the list */
            working_range = apr_array_make(req_pool, 1, sizeof(char*));
            for(item = valuenode->data.sequence.items.start;
                item < valuenode->data.sequence.items.top;
                item++) {
                node = yaml_document_get_node(&document, (int)*item);
                if(node->type != YAML_SCALAR_NODE) { /* only scalars allowed */
                    range_request_warn(rr,
                                       "%s: malformed cluster definition %s",
                                       cluster, cluster_file);
                    yaml_document_delete(&document);
                    yaml_parser_delete(&parser);
                    return set_new(pool, 0);
                } else { /* add to the working set */
                    /* include it in () because we're going to comma it
                       together later */
                    *(char**)apr_array_push(working_range) =
                        apr_psprintf(pool, "(%s)", _substitute_dollars(pool,
                          cluster, node->data.scalar.value));
                }
            }
            /* glue the list items together with commas */
            set_add(sections, cur_section,
                    apr_array_pstrcat(pool, working_range, ','));
        }
    }

    /* Add a "KEYS" toplevel key that lists all the other keys */
    /* TODO: make an error if somebody tries to specify KEYS manually? */
    set_add(sections, "KEYS", _join_elements(pool, ',', sections));
    yaml_document_delete(&document);
    yaml_parser_delete(&parser);
    return sections;
}
Beispiel #10
0
static set* _cluster_keys(range_request* rr, apr_pool_t* pool,
                          const char* cluster, const char* cluster_file)
{
    char line[32768];
    char* p;
    int ovector[30];
    apr_array_header_t* working_range;
    set* sections;
    char* section;
    char* cur_section;
    apr_pool_t* req_pool = range_request_pool(rr);
    int line_no;
    FILE* fp = fopen(cluster_file, "r");

    if (!fp) {
        range_request_warn(rr, "%s: %s not readable", cluster, cluster_file);
        return set_new(pool, 0);
    }

    if (!include_re) {
        const char* error;
        include_re = pcre_compile(INCLUDE_RE, 0, &error, ovector, NULL);
        assert(include_re);

        exclude_re = pcre_compile(EXCLUDE_RE, 0, &error, ovector, NULL);
        assert(exclude_re);
    }

    sections = set_new(pool, 0);
    section = cur_section = NULL;


    working_range = apr_array_make(req_pool, 1, sizeof(char*));
    line_no = 0;
    while (fgets(line, sizeof line, fp)) {
        int len;
        int count;
        line_no++;
        line[sizeof line - 1] = '\0';
        len = strlen(line);
        if (len+1 >= sizeof(line) && line[len - 1] != '\n') {
            /* incomplete line */
            fprintf(stderr, "%s:%d lines > 32767 chars not supported\n", cluster_file, line_no);
            exit(-1);
        }

        line[--len] = '\0'; /* get rid of the \n */
        for (p = line; *p; ++p)
            if (*p == '#') {
                *p = '\0';
                break;
            }

        len = strlen(line);
        if (len == 0) continue;

        for (p = &line[len - 1]; isspace(*p); --p) {
            *p = '\0';
            --len;
        }

        if (!*line) continue;

        if (!(isspace(*line))) {
            cur_section = apr_pstrdup(pool, line);
            continue;
        }

        if (section && strcmp(cur_section, section) != 0) {
            set_add(sections, section, 
                    apr_array_pstrcat(pool, working_range, ','));
            working_range = apr_array_make(req_pool, 1, sizeof(char*));
        }

        section = cur_section;
        count = pcre_exec(include_re, NULL, line, len,
                          0, 0, ovector, 30);
        if (count > 0) {
            line[ovector[3]] = '\0';
            *(char**)apr_array_push(working_range) =
                apr_psprintf(pool, "(%s)",
                             _substitute_dollars(pool, cluster, &line[ovector[2]]));
            continue;
        }

        count = pcre_exec(exclude_re, NULL, line, len,
                          0, 0, ovector, 30);
        if (count > 0) {
            line[ovector[3]] = '\0';
            *(char**)apr_array_push(working_range) =
                apr_psprintf(pool, "-(%s)",
                             _substitute_dollars(pool, cluster, &line[ovector[2]]));
        }

    }
    fclose(fp);

    if (cur_section)
        set_add(sections, cur_section,
                apr_array_pstrcat(pool, working_range, ','));

    set_add(sections, "KEYS", _join_elements(pool, ',', sections));
    set_add(sections, "UP", set_get_data(sections, "CLUSTER"));
    if (set_get(sections, "ALL") && set_get(sections, "CLUSTER"))
        set_add(sections, "DOWN",
                apr_psprintf(pool, "(%s)-(%s)",
                             (char*)set_get_data(sections, "ALL"),
                             (char*)set_get_data(sections, "CLUSTER")));
    return sections;
}
/* Set the value of a config variabe, strings only */
static const char *set_config_value(cmd_parms *cmd, void *mconfig,
                                    const char *value)
{
    settings_rec *cfg;

    cfg = (settings_rec *) mconfig;

    char name[50];
    sprintf( name, "%s", cmd->cmd->name );

    /*
     * Apply restrictions on attributes.
     */
    if( strlen(value) == 0 ) {
        return apr_psprintf(cmd->pool, "%s not allowed to be NULL", name);
    }

    /* Domain to set the cookie in */
    if( strcasecmp(name, "QS2CookieDomain") == 0 ) {

        if( value[0] != '.' ) {
            return "QS2CookieDomain values must begin with a dot";
        }

        if( ap_strchr_c( &value[1], '.' ) == NULL ) {
            return "QS2CookieDomain values must contain at least one embedded dot";
        }

        // immediately format it for the cookie value, as that's the only
        // place we'll be using it.
        cfg->cookie_domain =
            apr_pstrcat( cmd->pool, "domain=", value, "; ", NULL );

    /* Prefix for all keys set in the cookie */
    } else if( strcasecmp(name, "QS2CookiePrefix") == 0 ) {
        cfg->cookie_prefix     = apr_pstrdup(cmd->pool, value);

    /* Use this query string argument for the cookie name */
    } else if( strcasecmp(name, "QS2CookieName") == 0 ) {
        cfg->cookie_name       = apr_pstrdup(cmd->pool, value);

    /* Use this query string argument for the cookie name */
    } else if( strcasecmp(name, "QS2CookieNameFrom") == 0 ) {
        cfg->cookie_name_from  = apr_pstrdup(cmd->pool, value);

    /* Use this delimiter for pairs of key/values */
    } else if( strcasecmp(name, "QS2CookiePairDelimiter") == 0 ) {

        if( strcspn( value, "=" ) == 0 ) {
            return apr_psprintf(cmd->pool,
                "Variable %s may not be '=' -- illegal in cookie values", name);
        }

        cfg->cookie_pair_delimiter  = apr_pstrdup(cmd->pool, value);

    /* Use this delimiter between a key and a value */
    } else if( strcasecmp(name, "QS2CookieKeyValueDelimiter") == 0 ) {

        if( strcspn( value, "=" ) == 0 ) {
            return apr_psprintf(cmd->pool,
                "Variable %s may not be '=' -- illegal in cookie values", name);
        }

        cfg->cookie_key_value_delimiter  = apr_pstrdup(cmd->pool, value);

    /* Maximum size of all the key/value pairs */
    } else if( strcasecmp(name, "QS2CookieMaxSize") == 0 ) {

        // this has to be a number
        if( apr_isdigit(*value) && apr_isdigit(value[strlen(value) - 1]) ) {
            cfg->cookie_max_size   = atol(apr_pstrdup(cmd->pool, value));
        } else {
            return apr_psprintf(cmd->pool,
                "Variable %s must be a number, not %s", name, value);
        }

    /* Expiry time, in seconds after the request */
    } else if( strcasecmp(name, "QS2CookieExpires") == 0 ) {

        // this has to be a number
        if( apr_isdigit(*value) && apr_isdigit(value[strlen(value) - 1]) ) {
            cfg->cookie_expires = atol(apr_pstrdup(cmd->pool, value));
        } else {
            return apr_psprintf(cmd->pool,
                "Variable %s must be a number, not %s", name, value);
        }

    /* all the keys that will not be put into the cookie */
    } else if( strcasecmp(name, "QS2CookieIgnore") == 0 ) {

        // following tutorial here:
        // http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-19.html
        const char *str                                = apr_pstrdup(cmd->pool, value);
        *(const char**)apr_array_push(cfg->qs_ignore) = str;

        _DEBUG && fprintf( stderr, "qs ignore = %s\n", str );

        char *ary = apr_array_pstrcat( cmd->pool, cfg->qs_ignore, '-' );
        _DEBUG && fprintf( stderr, "qs ignore as str = %s\n", ary );

    } else {
        return apr_psprintf(cmd->pool, "No such variable %s", name);
    }

    return NULL;
}
/* Set the value of a config variabe, strings only */
static const char *set_config_value(cmd_parms *cmd, void *mconfig,
                                    const char *value)
{
    cookietrack_settings_rec *dcfg;

    dcfg = (cookietrack_settings_rec *) mconfig;

    char name[50];
    sprintf( name, "%s", cmd->cmd->name );

    /* Unfortunately, C does not have the equivalent of Perls
       $struct->$name = $value. So we're using a switch instead.
       Suggestions welcome.
    */
    /* Oh hey, switch statements aren't for strings, so we're
       going to be using if (strcasecmp(name, "y") == 0) {
       instead. sexy times!
    */

    /*
     * Apply restrictions on attributes.
     */
    if( strlen(value) == 0 ) {
        return apr_psprintf(cmd->pool, "%s not allowed to be NULL", name);
    }

    /* Name of the cookie header to send */
    if( strcasecmp(name, "CookieHeaderName") == 0 ) {
        dcfg->header_name   = apr_pstrdup(cmd->pool, value);

    /* Name of the note to use in the logs */
    } else if( strcasecmp(name, "CookieNoteName") == 0 ) {
        dcfg->note_name     = apr_pstrdup(cmd->pool, value);

    /* Value to use if setting a DNT cookie */
    } else if( strcasecmp(name, "CookieDNTValue") == 0 ) {
        dcfg->dnt_value     = apr_pstrdup(cmd->pool, value);

    /* Cookie style to sue */
    } else if( strcasecmp(name, "CookieStyle") == 0 ) {

        if( strcasecmp(value, "Netscape") == 0 ) {
            dcfg->style = CT_NETSCAPE;

        } else if( (strcasecmp(value, "Cookie") == 0)
                 || (strcasecmp(value, "RFC2109") == 0) ) {
            dcfg->style = CT_COOKIE;

        } else if( (strcasecmp(value, "Cookie2") == 0)
                 || (strcasecmp(value, "RFC2965") == 0) ) {
            dcfg->style = CT_COOKIE2;

        } else {
            return apr_psprintf(cmd->pool, "Invalid %s: %s", name, value);
        }

    /* Name of the note to use in the logs */
    } else if( strcasecmp(name, "CookieIPHeader") == 0 ) {
        dcfg->cookie_ip_header  = apr_pstrdup(cmd->pool, value);

    /* Domain to set the cookie in */
    } else if( strcasecmp(name, "CookieDomain") == 0 ) {

        if( value[0] != '.' ) {
            return "CookieDomain values must begin with a dot";
        }

        if( ap_strchr_c( &value[1], '.' ) == NULL ) {
            return "CookieDomain values must contain at least one embedded dot";
        }

        dcfg->cookie_domain = apr_pstrdup(cmd->pool, value);

    /* Name of the cookie */
    } else if( strcasecmp(name, "CookieName") == 0 ) {
        dcfg->cookie_name = apr_pstrdup(cmd->pool, value);

        /* build regex to compare against */
        set_and_comp_regexp(dcfg, cmd->pool, value);

        if (dcfg->regexp == NULL) {
            return "Regular expression could not be compiled.";
        }

        if (dcfg->regexp->re_nsub + 1 != NUM_SUBS) {
            return apr_psprintf(cmd->pool, "Invalid cookie name: %s", value);
        }

    } else if( strcasecmp(name, "CookieDNTExempt") == 0 ) {

        // following tutorial here:
        // http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-19.html
        const char *str                                 = apr_pstrdup(cmd->pool, value);
        *(const char**)apr_array_push(dcfg->dnt_exempt) = str;

        _DEBUG && fprintf( stderr, "dnt exempt = %s\n", str );

        char *ary = apr_array_pstrcat( cmd->pool, dcfg->dnt_exempt, '-' );
        _DEBUG && fprintf( stderr, "dnt exempt as str = %s\n", ary );

    } else {
        return apr_psprintf(cmd->pool, "No such variable %s", name);
    }

    return NULL;
}
Beispiel #13
0
static int rpaf_post_read_request(request_rec *r) {
    char *fwdvalue, *val, *mask, *last_val;
    int i;
    apr_port_t tmpport;
    apr_pool_t *tmppool;
    const char *header_ip = NULL, *header_host = NULL, *header_https = NULL, *header_port = NULL;
    rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(r->server->module_config,
                                                                   &rpaf_module);

    if (!cfg->enable)
        return DECLINED;

    /* this overcomes an issue when mod_rewrite causes this to get called again
       and the environment value is lost for HTTPS. This is the only thing that
       is lost and we do not need to process any further after restoring the
       value. Note that this check uses the *per-request* note - otherwise we
       would shortcut here for every subsequent request */
    const char *rpaf_https = apr_table_get(r->notes, "rpaf_https");
    if (rpaf_https) {
        apr_table_set(r->subprocess_env, "HTTPS", rpaf_https);
        return DECLINED;
    }

    /* check if the remote_addr is in the allowed proxy IP list */
    if (is_in_array(r->DEF_ADDR, cfg->proxy_ips) != 1) {
        if (cfg->forbid_if_not_proxy)
            return HTTP_FORBIDDEN;
        return DECLINED;
    }

    /* TODO: We should not just assume that we should fallback to
       X-Forwarded-For as this could pose a security risk, keeping
       this for now to keep our behaviour consistant */
    header_ip = cfg->headername;
    if (header_ip)
      fwdvalue = (char *)apr_table_get(r->headers_in, header_ip);
    if (!header_ip || !fwdvalue)
    {
      header_ip = "X-Forwarded-For";
      fwdvalue  = (char *)apr_table_get(r->headers_in, header_ip);
    }

    /* if there was no forwarded for header then we dont do anything */
    if (!fwdvalue)
        return DECLINED;

    /* split up the list of forwarded IPs */
    apr_array_header_t *arr = apr_array_make(r->pool, 4, sizeof(char *));
    while ((val = strsep(&fwdvalue, ",")) != NULL) {
        /* strip leading and trailing whitespace */
        while(isspace(*val))
            ++val;
        for (i = strlen(val) - 1; i > 0 && isspace(val[i]); i--)
            val[i] = '\0';
        if (rpaf_looks_like_ip(val))
            *(char **)apr_array_push(arr) = apr_pstrdup(r->pool, val);
    }

    /* if there were no IPs, then there is nothing to do */
    if (apr_is_empty_array(arr))
        return DECLINED;

    /* get the last IP and check if it is in our list of proxies */
    if ((last_val = last_not_in_array(r, arr, cfg->proxy_ips)) == NULL)
        return DECLINED;

    /* if we are cleaning up the headers then we need to correct the forwarded IP list */
    if (cfg->clean_headers)
    {
        /* pop the proxy's IP from the list */
        apr_array_pop(arr);
        if (apr_is_empty_array(arr))
            apr_table_unset(r->headers_in, header_ip);
        else {
            char *ip_list = apr_array_pstrcat(r->pool, arr, ',');
            apr_table_set(r->headers_in, header_ip, ip_list);
        }
    }

    rpaf_cleanup_rec *rcr = (rpaf_cleanup_rec *)apr_pcalloc(r->pool, sizeof(rpaf_cleanup_rec));
    rcr->old_ip = apr_pstrdup(r->DEF_POOL, r->DEF_IP);
    rcr->r = r;
    apr_pool_cleanup_register(r->pool, (void *)rcr, rpaf_cleanup, apr_pool_cleanup_null);
    r->DEF_IP = apr_pstrdup(r->DEF_POOL, last_val);
    memcpy(&rcr->old_addr, r->DEF_ADDR, sizeof(apr_sockaddr_t));

    tmppool = r->DEF_ADDR->pool;
    tmpport = r->DEF_ADDR->port;
    apr_sockaddr_t *tmpsa;
    int ret = apr_sockaddr_info_get(&tmpsa, r->DEF_IP, APR_UNSPEC, tmpport, 0, tmppool);
    if (ret == APR_SUCCESS)
        memcpy(r->DEF_ADDR, tmpsa, sizeof(apr_sockaddr_t));
    if (cfg->sethostname) {
        const char *hostvalue;
        header_host = "X-Forwarded-Host";
        hostvalue   = apr_table_get(r->headers_in, header_host);
        if (!hostvalue) {
            header_host = "X-Host";
            hostvalue   = apr_table_get(r->headers_in, header_host);
        }

        if (!hostvalue) {
            header_host = NULL;
        } else {
            apr_array_header_t *arr = apr_array_make(r->pool, 0, sizeof(char*));
            while (*hostvalue && (val = ap_get_token(r->pool, &hostvalue, 1))) {
                *(char **)apr_array_push(arr) = apr_pstrdup(r->pool, val);
                if (*hostvalue != '\0')
                  ++hostvalue;
            }

            apr_table_set(r->headers_in, "Host", apr_pstrdup(r->pool, ((char **)arr->elts)[((arr->nelts)-1)]));
            r->hostname = apr_pstrdup(r->pool, ((char **)arr->elts)[((arr->nelts)-1)]);
            ap_update_vhost_from_headers(r);
        }
    }

    if (cfg->sethttps) {
        const char *httpsvalue, *scheme;
        header_https = "X-Forwarded-HTTPS";
        httpsvalue   = apr_table_get(r->headers_in, header_https);
        if (!httpsvalue) {
            header_https = "X-HTTPS";
            httpsvalue   = apr_table_get(r->headers_in, header_https);
        }

        if (!httpsvalue) {
            header_https = "X-Forwarded-Proto";
            httpsvalue   = apr_table_get(r->headers_in, header_https);
            if (!httpsvalue) {
              header_https = "X-Forwarded-Protocol";
              httpsvalue   = apr_table_get(r->headers_in, header_https);
            }
            if (httpsvalue) {
                if (strcmp(httpsvalue, cfg->https_scheme) == 0) {
                    /* set a per-request note to get around an issue with mod_rewrite
                       (explained in an earlier comment), and a per-connection note
                       to allow our version of ssl_is_https() to work.
                     */
                    apr_table_set(r->notes, "rpaf_https", "on");
                    apr_table_set(r->connection->notes, "rpaf_https", "on");
                    apr_table_set(r->subprocess_env   , "HTTPS"     , "on");
                    scheme = cfg->https_scheme;
                } else {
                    scheme = cfg->orig_scheme;
                }
            } else {
                header_https = NULL;
                scheme       = cfg->orig_scheme;
            }
        } else {
            if(strcmp(httpsvalue, "on") == 0 || strcmp(httpsvalue, "On") == 0) {
              apr_table_set(r->notes, "rpaf_https", "on");
              apr_table_set(r->connection->notes, "rpaf_https", "on");
              apr_table_set(r->subprocess_env   , "HTTPS"     , "on");
              scheme = cfg->https_scheme;
            } else {
              scheme = cfg->orig_scheme;
            }
        }

        #if AP_SERVER_MINORVERSION_NUMBER > 1 && AP_SERVER_PATCHLEVEL_NUMBER > 2
        r->server->server_scheme = scheme;
        #endif
    }

     if (cfg->setport) {
        const char *portvalue;
        header_port = "X-Forwarded-Port";
        portvalue   = apr_table_get(r->headers_in, header_port);
        if (!portvalue) {
            header_port = "X-Port";
            portvalue   = apr_table_get(r->headers_in, header_port);
        }

        if (!portvalue) {
            header_port     = NULL;
            r->server->port = cfg->orig_port;
        } else {
            r->server->port    = atoi(portvalue);
            r->parsed_uri.port = r->server->port;
        }
    }

    if (cfg->clean_headers) {
        if (header_host ) apr_table_unset(r->headers_in, header_host );
        if (header_https) apr_table_unset(r->headers_in, header_https);
        if (header_port ) apr_table_unset(r->headers_in, header_port );
    }

    return DECLINED;
}