diff options
author | Yann Ylavic <ylavic@apache.org> | 2018-02-16 14:56:15 +0000 |
---|---|---|
committer | Yann Ylavic <ylavic@apache.org> | 2018-02-16 14:56:15 +0000 |
commit | 48a8c0a962a64d6283e8163d0d72323f405d6d51 (patch) | |
tree | 99b7c00d9c311011008ada8ba9993503058b692d | |
parent | d0859a04de81f4c6c74ba6993acbdebaa1101751 (diff) | |
parent | 7301e2d3762adffad70753bea09e6227351eed59 (diff) | |
download | httpd-48a8c0a962a64d6283e8163d0d72323f405d6d51.tar.gz |
Follow up to r1821624: sync with 2.4.x.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x-mpm_fdqueue@1824502 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | CHANGES | 22 | ||||
-rw-r--r-- | STATUS | 89 | ||||
-rw-r--r-- | include/ap_mmn.h | 5 | ||||
-rw-r--r-- | include/ap_regex.h | 22 | ||||
-rw-r--r-- | modules/aaa/mod_auth_digest.c | 241 | ||||
-rw-r--r-- | modules/aaa/mod_authnz_ldap.c | 10 | ||||
-rw-r--r-- | modules/cache/mod_cache_socache.c | 3 | ||||
-rw-r--r-- | modules/proxy/proxy_util.c | 6 | ||||
-rw-r--r-- | modules/session/mod_session.c | 13 | ||||
-rw-r--r-- | server/core.c | 58 | ||||
-rw-r--r-- | server/protocol.c | 76 | ||||
-rw-r--r-- | server/util_pcre.c | 35 |
12 files changed, 311 insertions, 269 deletions
@@ -4,6 +4,28 @@ Changes with Apache 2.4.30 *) mpm_queue: Put fdqueue code in common for MPMs event and worker. [Yann Ylavic] + *) mod_session: Strip Session header when SessionEnv is on. [Yann Ylavic] + + *) mod_cache_socache: Fix caching of empty headers up to carriage return. + [Yann Ylavic] + + *) core: For consistency, ensure that read lines are NUL terminated on any + error, not only on buffer full. [Yann Ylavic] + + *) mod_authnz_ldap: Fix language long names detection as short name. + [Yann Ylavic] + + *) mod_proxy: Worker schemes and hostnames which are too large are no + longer fatal errors; it is logged and the truncated values are stored. + [Jim Jagielski] + + *) regex: Allow to configure global/default options for regexes, like + caseless matching or extended format. [Yann Ylavic] + + *) mod_auth_digest: Actually use the secret when generating nonces. This change + may cause problems if used with round robin load balancers. PR 54637 + [Stefan Fritsch] + *) mod_proxy: Allow setting options to globally defined balancer from ProxyPass used in VirtualHost. Balancers are now merged using the new merge_balancers method which merges the balancers options. [Jan Kaluza] @@ -118,48 +118,71 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - -PATCHES PROPOSED TO BACKPORT FROM TRUNK: - [ New proposals should be added at the end of the list ] - - *) proxy_util: Schemes and hostnames that are "too long" are - no longer automatically fatal errors but are instead logged - and truncated, at which point the admin can determine if that - is OK or not. - trunk patch: http://svn.apache.org/r1823482 - 2.4.x patch: trunk works - +1: jim, minfrin - *) mod_proxy: Provide an RFC1035 compliant version of the hostname in the proxy_worker_shared structure. PR62085 trunk patch: http://svn.apache.org/r1824176 - 2.4.x patch: https://svn.apache.org/repos/asf/httpd/httpd/patches/2.4.x/proxy-rfc1035-hostname.diff - +1: minfrin, jim, + +1: minfrin, jim, ylavic jailletc36: is message 010118 still needed? Or at least mitigated with something like: "for third party proxy module usage only"? Also, does it require a ap_mmn.h update? + minfrin: message 010118 toned down, MMN bump updated, clash with r1823482 resolved, s/APLOG_NOTICE/APLOG_INFO/ + http://svn.apache.org/r1824460 + http://svn.apache.org/r1824482 + 2.4.x patch: https://svn.apache.org/repos/asf/httpd/httpd/patches/2.4.x/proxy-rfc1035-hostname-v3.diff - *) core: For consistency, ensure that read lines are NUL terminated on any - error, not only on buffer full. - trunk patch: http://svn.apache.org/r1824303 - 2.4.x patch: trunk works (modulo CHANGES) - +1: ylavic - - *) mod_authnz_ldap: Fix language long names detection as short name. - trunk patch: http://svn.apache.org/r1824336 - 2.4.x patch: trunk works (modulo CHANGES) - +1: ylavic - *) regex: Allow to configure global/default options for regexes, like - caseless matching or extended format. - trunk patch: http://svn.apache.org/r1824339 - 2.4.x patch: http://home.apache.org/~ylavic/patches/httpd-2.4.x-global_regex_options.patch - +1: ylavic +PATCHES PROPOSED TO BACKPORT FROM TRUNK: + [ New proposals should be added at the end of the list ] - *) mod_cache_socache: Fix caching of empty headers up to carriage return. - trunk patch: http://svn.apache.org/r1824343 - 2.4.x patch: trunk works (modulo CHANGES) - +1: ylavic + *) mpm_queue: Put fdqueue code in common for MPMs event and worker. + trunk patch: http://svn.apache.org/r1821624 + http://svn.apache.org/r1821625 + http://svn.apache.org/r1821626 + http://svn.apache.org/r1821627 + http://svn.apache.org/r1821629 + http://svn.apache.org/r1821632 + http://svn.apache.org/r1821635 + http://svn.apache.org/r1821639 + http://svn.apache.org/r1821644 + http://svn.apache.org/r1821647 + http://svn.apache.org/r1821648 + http://svn.apache.org/r1821649 + http://svn.apache.org/r1821650 + http://svn.apache.org/r1821651 + http://svn.apache.org/r1821659 + http://svn.apache.org/r1821660 + http://svn.apache.org/r1822366 + http://svn.apache.org/r1822367 + http://svn.apache.org/r1824381 + 2.4.x patch: svn merge ^/httpd/httpd/branches/2.4.x-mpm_fdqueue . + (http://home.apache.org/~ylavic/patches/httpd-2.4.x-mpm_fdqueue.patch) + +1: ylavic, minfrin (with mmn bump for mpm_fdqueue.h) + ylavic: The branch merge helps resolve move conflicts since event and + worker fdqueue.[ch] differ(ed) between 2.4.x and trunk. The patch + is provided only to help review. + + *) mpm_event: Do lingering close in worker(s). + trunk patch: http://svn.apache.org/r1823047 + http://svn.apache.org/r1824454 + http://svn.apache.org/r1824463 + http://svn.apache.org/r1824464 + http://svn.apache.org/r1824497 + 2.4.x patch: http://home.apache.org/~ylavic/patches/httpd-2.4.x-event-lingering_close_in_worker.patch + (trunk works if mpm_queue above is merged first, otherwise + the mpm_queue branch can also be synchronized after this + merge, YMMV :) + +1: ylavic, + + *) mod_ssl: Introduce SSLPolicy/SSLPolicyDefine directives. + trunk patch: http://svn.apache.org/r1805182 + http://svn.apache.org/r1805186 + http://svn.apache.org/r1808335 + http://svn.apache.org/r1811475 + http://svn.apache.org/r1817381 + http://svn.apache.org/r1817894 + 2.4.x patch: https://svn.apache.org/repos/asf/httpd/httpd/patches/2.4.x/mod_ssl_policy.diff + +1: icing, minfrin + minfrin: 2.4.x patch not applying for me, trunk patches work PATCHES/ISSUES THAT ARE BEING WORKED diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 70b9c621bc..af3a8a5590 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -507,6 +507,9 @@ * semantics * 20120211.73 (2.4.30-dev) Add failontimeout_set, growth_set and lbmethod_set * to proxy_balancer struct + * 20120211.74 (2.4.30-dev) Add AP_REG_DOLLAR_ENDONLY, ap_regcomp_get_default_cflags + * ap_regcomp_set_default_cflags and + * ap_regcomp_default_cflag_by_name */ #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ @@ -514,7 +517,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20120211 #endif -#define MODULE_MAGIC_NUMBER_MINOR 73 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 74 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/ap_regex.h b/include/ap_regex.h index be41226bee..ec6908cdc9 100644 --- a/include/ap_regex.h +++ b/include/ap_regex.h @@ -77,6 +77,8 @@ extern "C" { #define AP_REG_NOMEM 0x20 /* nomem in our code */ #define AP_REG_DOTALL 0x40 /* perl's /s flag */ +#define AP_REG_DOLLAR_ENDONLY 0x200 /* '$' matches at end of subject string only */ + #define AP_REG_MATCH "MATCH_" /** suggested prefix for ap_regname */ /* Error values: */ @@ -103,6 +105,26 @@ typedef struct { /* The functions */ /** + * Get default compile flags + * @return Bitwise OR of AP_REG_* flags + */ +AP_DECLARE(int) ap_regcomp_get_default_cflags(void); + +/** + * Set default compile flags + * @param cflags Bitwise OR of AP_REG_* flags + */ +AP_DECLARE(void) ap_regcomp_set_default_cflags(int cflags); + +/** + * Get the AP_REG_* corresponding to the string. + * @param name The name (i.e. AP_REG_<name>) + * @return The AP_REG_*, or zero if the string is unknown + * + */ +AP_DECLARE(int) ap_regcomp_default_cflag_by_name(const char *name); + +/** * Compile a regular expression. * @param preg Returned compiled regex * @param regex The regular expression string diff --git a/modules/aaa/mod_auth_digest.c b/modules/aaa/mod_auth_digest.c index e99cb3b3f1..a8f2cc52aa 100644 --- a/modules/aaa/mod_auth_digest.c +++ b/modules/aaa/mod_auth_digest.c @@ -26,20 +26,13 @@ * reports to the Apache bug-database, or send them directly to me * at ronald@innovation.ch. * - * Requires either /dev/random (or equivalent) or the truerand library, - * available for instance from - * ftp://research.att.com/dist/mab/librand.shar - * * Open Issues: * - qop=auth-int (when streams and trailer support available) * - nonce-format configurability * - Proxy-Authorization-Info header is set by this module, but is * currently ignored by mod_proxy (needs patch to mod_proxy) - * - generating the secret takes a while (~ 8 seconds) if using the - * truerand library * - The source of the secret should be run-time directive (with server - * scope: RSRC_CONF). However, that could be tricky when trying to - * choose truerand vs. file... + * scope: RSRC_CONF) * - shared-mem not completely tested yet. Seems to work ok for me, * but... (definitely won't work on Windoze) * - Sharing a realm among multiple servers has following problems: @@ -52,6 +45,8 @@ * captures a packet sent to one server and sends it to another * one. Should we add "AuthDigestNcCheck Strict"? * - expired nonces give amaya fits. + * - MD5-sess and auth-int are not yet implemented. An incomplete + * implementation has been removed and can be retrieved from svn history. */ #include "apr_sha1.h" @@ -94,7 +89,6 @@ typedef struct digest_config_struct { apr_array_header_t *qop_list; apr_sha1_ctx_t nonce_ctx; apr_time_t nonce_lifetime; - const char *nonce_format; int check_nc; const char *algorithm; char *uri_list; @@ -112,7 +106,8 @@ typedef struct digest_config_struct { #define NONCE_HASH_LEN (2*APR_SHA1_DIGESTSIZE) #define NONCE_LEN (int )(NONCE_TIME_LEN + NONCE_HASH_LEN) -#define SECRET_LEN 20 +#define SECRET_LEN 20 +#define RETAINED_DATA_ID "mod_auth_digest" /* client list definitions */ @@ -121,7 +116,6 @@ typedef struct hash_entry { unsigned long key; /* the key for this entry */ struct hash_entry *next; /* next entry in the bucket */ unsigned long nonce_count; /* for nonce-count checking */ - char ha1[2*APR_MD5_DIGESTSIZE+1]; /* for algorithm=MD5-sess */ char last_nonce[NONCE_LEN+1]; /* for one-time nonce's */ } client_entry; @@ -170,7 +164,7 @@ typedef union time_union { unsigned char arr[sizeof(apr_time_t)]; } time_rec; -static unsigned char secret[SECRET_LEN]; +static unsigned char *secret; /* client-list, opaque, and one-time-nonce stuff */ @@ -228,35 +222,11 @@ static apr_status_t cleanup_tables(void *not_used) return APR_SUCCESS; } -static apr_status_t initialize_secret(server_rec *s) -{ - apr_status_t status; - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01757) - "generating secret for digest authentication ..."); - -#if APR_HAS_RANDOM - status = apr_generate_random_bytes(secret, sizeof(secret)); -#else -#error APR random number support is missing; you probably need to install the truerand library. -#endif - - if (status != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, status, s, APLOGNO(01758) - "error generating secret"); - return status; - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01759) "done"); - - return APR_SUCCESS; -} - static void log_error_and_cleanup(char *msg, apr_status_t sts, server_rec *s) { ap_log_error(APLOG_MARK, APLOG_ERR, sts, s, APLOGNO(01760) - "%s - all nonce-count checking, one-time nonces, and " - "MD5-sess algorithm disabled", msg); + "%s - all nonce-count checking and one-time nonces" + "disabled", msg); cleanup_tables(NULL); } @@ -386,16 +356,32 @@ static int initialize_tables(server_rec *s, apr_pool_t *ctx) static int pre_init(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) { apr_status_t rv; + void *retained; rv = ap_mutex_register(pconf, client_mutex_type, NULL, APR_LOCK_DEFAULT, 0); - if (rv == APR_SUCCESS) { - rv = ap_mutex_register(pconf, opaque_mutex_type, NULL, APR_LOCK_DEFAULT, - 0); - } - if (rv != APR_SUCCESS) { - return rv; - } + if (rv != APR_SUCCESS) + return !OK; + rv = ap_mutex_register(pconf, opaque_mutex_type, NULL, APR_LOCK_DEFAULT, 0); + if (rv != APR_SUCCESS) + return !OK; + retained = ap_retained_data_get(RETAINED_DATA_ID); + if (retained == NULL) { + retained = ap_retained_data_create(RETAINED_DATA_ID, SECRET_LEN); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(01757) + "generating secret for digest authentication"); +#if APR_HAS_RANDOM + rv = apr_generate_random_bytes(retained, SECRET_LEN); +#else +#error APR random number support is missing +#endif + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, APLOGNO(01758) + "error generating secret"); + return !OK; + } + } + secret = retained; return OK; } @@ -408,10 +394,6 @@ static int initialize_module(apr_pool_t *p, apr_pool_t *plog, if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) return OK; - if (initialize_secret(s) != APR_SUCCESS) { - return !OK; - } - #if APR_HAS_SHARED_MEMORY /* Note: this stuff is currently fixed for the lifetime of the server, * i.e. even across restarts. This means that A) any shmem-size @@ -492,6 +474,16 @@ static void *create_digest_dir_config(apr_pool_t *p, char *dir) static const char *set_realm(cmd_parms *cmd, void *config, const char *realm) { digest_config_rec *conf = (digest_config_rec *) config; +#ifdef AP_DEBUG + int i; + + /* check that we got random numbers */ + for (i = 0; i < SECRET_LEN; i++) { + if (secret[i] != 0) + break; + } + ap_assert(i < SECRET_LEN); +#endif /* The core already handles the realm, but it's just too convenient to * grab it ourselves too and cache some setups. However, we need to @@ -505,7 +497,7 @@ static const char *set_realm(cmd_parms *cmd, void *config, const char *realm) * and directives outside a virtual host section) */ apr_sha1_init(&conf->nonce_ctx); - apr_sha1_update_binary(&conf->nonce_ctx, secret, sizeof(secret)); + apr_sha1_update_binary(&conf->nonce_ctx, secret, SECRET_LEN); apr_sha1_update_binary(&conf->nonce_ctx, (const unsigned char *) realm, strlen(realm)); @@ -599,8 +591,7 @@ static const char *set_nonce_lifetime(cmd_parms *cmd, void *config, static const char *set_nonce_format(cmd_parms *cmd, void *config, const char *fmt) { - ((digest_config_rec *) config)->nonce_format = fmt; - return "AuthDigestNonceFormat is not implemented (yet)"; + return "AuthDigestNonceFormat is not implemented"; } static const char *set_nc_check(cmd_parms *cmd, void *config, int flag) @@ -621,7 +612,7 @@ static const char *set_algorithm(cmd_parms *cmd, void *config, const char *alg) { if (!strcasecmp(alg, "MD5-sess")) { return "AuthDigestAlgorithm: ERROR: algorithm `MD5-sess' " - "is not fully implemented"; + "is not implemented"; } else if (strcasecmp(alg, "MD5")) { return apr_pstrcat(cmd->pool, "Invalid algorithm in AuthDigestAlgorithm: ", alg, NULL); @@ -1147,7 +1138,7 @@ static const char *gen_nonce(apr_pool_t *p, apr_time_t now, const char *opaque, static client_entry *gen_client(const request_rec *r) { unsigned long op; - client_entry new_entry = { 0, NULL, 0, "", "" }, *entry; + client_entry new_entry = { 0, NULL, 0, "" }, *entry; if (!opaque_cntr) { return NULL; @@ -1168,92 +1159,6 @@ static client_entry *gen_client(const request_rec *r) /* - * MD5-sess code. - * - * If you want to use algorithm=MD5-sess you must write get_userpw_hash() - * yourself (see below). The dummy provided here just uses the hash from - * the auth-file, i.e. it is only useful for testing client implementations - * of MD5-sess . - */ - -/* - * get_userpw_hash() will be called each time a new session needs to be - * generated and is expected to return the equivalent of - * - * h_urp = ap_md5(r->pool, - * apr_pstrcat(r->pool, username, ":", ap_auth_name(r), ":", passwd)) - * ap_md5(r->pool, - * (unsigned char *) apr_pstrcat(r->pool, h_urp, ":", resp->nonce, ":", - * resp->cnonce, NULL)); - * - * or put differently, it must return - * - * MD5(MD5(username ":" realm ":" password) ":" nonce ":" cnonce) - * - * If something goes wrong, the failure must be logged and NULL returned. - * - * You must implement this yourself, which will probably consist of code - * contacting the password server with the necessary information (typically - * the username, realm, nonce, and cnonce) and receiving the hash from it. - * - * TBD: This function should probably be in a separate source file so that - * people need not modify mod_auth_digest.c each time they install a new - * version of apache. - */ -static const char *get_userpw_hash(const request_rec *r, - const digest_header_rec *resp, - const digest_config_rec *conf) -{ - return ap_md5(r->pool, - (unsigned char *) apr_pstrcat(r->pool, conf->ha1, ":", resp->nonce, - ":", resp->cnonce, NULL)); -} - - -/* Retrieve current session H(A1). If there is none and "generate" is - * true then a new session for MD5-sess is generated and stored in the - * client struct; if generate is false, or a new session could not be - * generated then NULL is returned (in case of failure to generate the - * failure reason will have been logged already). - */ -static const char *get_session_HA1(const request_rec *r, - digest_header_rec *resp, - const digest_config_rec *conf, - int generate) -{ - const char *ha1 = NULL; - - /* return the current sessions if there is one */ - if (resp->opaque && resp->client && resp->client->ha1[0]) { - return resp->client->ha1; - } - else if (!generate) { - return NULL; - } - - /* generate a new session */ - if (!resp->client) { - resp->client = gen_client(r); - } - if (resp->client) { - ha1 = get_userpw_hash(r, resp, conf); - if (ha1) { - memcpy(resp->client->ha1, ha1, sizeof(resp->client->ha1)); - } - } - - return ha1; -} - - -static void clear_session(const digest_header_rec *resp) -{ - if (resp->client) { - resp->client->ha1[0] = '\0'; - } -} - -/* * Authorization challenge generation code (for WWW-Authenticate) */ @@ -1291,8 +1196,7 @@ static void note_digest_auth_failure(request_rec *r, if (resp->opaque == NULL) { /* new client */ - if ((conf->check_nc || conf->nonce_lifetime == 0 - || !strcasecmp(conf->algorithm, "MD5-sess")) + if ((conf->check_nc || conf->nonce_lifetime == 0) && (resp->client = gen_client(r)) != NULL) { opaque = ltox(r->pool, resp->client->key); } @@ -1332,15 +1236,6 @@ static void note_digest_auth_failure(request_rec *r, memcpy(resp->client->last_nonce, nonce, NONCE_LEN+1); } - /* Setup MD5-sess stuff. Note that we just clear out the session - * info here, since we can't generate a new session until the request - * from the client comes in with the cnonce. - */ - - if (!strcasecmp(conf->algorithm, "MD5-sess")) { - clear_session(resp); - } - /* setup domain attribute. We want to send this attribute wherever * possible so that the client won't send the Authorization header * unnecessarily (it's usually > 200 bytes!). @@ -1606,24 +1501,9 @@ static const char *new_digest(const request_rec *r, { const char *ha1, *ha2, *a2; - if (resp->algorithm && !strcasecmp(resp->algorithm, "MD5-sess")) { - ha1 = get_session_HA1(r, resp, conf, 1); - if (!ha1) { - return NULL; - } - } - else { - ha1 = conf->ha1; - } + ha1 = conf->ha1; - if (resp->message_qop && !strcasecmp(resp->message_qop, "auth-int")) { - a2 = apr_pstrcat(r->pool, resp->method, ":", resp->uri, ":", - ap_md5(r->pool, (const unsigned char*) ""), NULL); - /* TBD */ - } - else { - a2 = apr_pstrcat(r->pool, resp->method, ":", resp->uri, NULL); - } + a2 = apr_pstrcat(r->pool, resp->method, ":", resp->uri, NULL); ha2 = ap_md5(r->pool, (const unsigned char *)a2); return ap_md5(r->pool, @@ -1871,8 +1751,7 @@ static int authenticate_digest_user(request_rec *r) } if (resp->algorithm != NULL - && strcasecmp(resp->algorithm, "MD5") - && strcasecmp(resp->algorithm, "MD5-sess")) { + && strcasecmp(resp->algorithm, "MD5")) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01789) "unknown algorithm `%s' received: %s", resp->algorithm, r->uri); @@ -2024,27 +1903,9 @@ static int add_auth_info(request_rec *r) /* calculate rspauth attribute */ - if (resp->algorithm && !strcasecmp(resp->algorithm, "MD5-sess")) { - ha1 = get_session_HA1(r, resp, conf, 0); - if (!ha1) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01795) - "internal error: couldn't find session " - "info for user %s", resp->username); - return !OK; - } - } - else { - ha1 = conf->ha1; - } + ha1 = conf->ha1; - if (resp->message_qop && !strcasecmp(resp->message_qop, "auth-int")) { - a2 = apr_pstrcat(r->pool, ":", resp->uri, ":", - ap_md5(r->pool,(const unsigned char *) ""), NULL); - /* TBD */ - } - else { - a2 = apr_pstrcat(r->pool, ":", resp->uri, NULL); - } + a2 = apr_pstrcat(r->pool, ":", resp->uri, NULL); ha2 = ap_md5(r->pool, (const unsigned char *)a2); resp_dig = ap_md5(r->pool, diff --git a/modules/aaa/mod_authnz_ldap.c b/modules/aaa/mod_authnz_ldap.c index 8cee7d47b1..98c48a8609 100644 --- a/modules/aaa/mod_authnz_ldap.c +++ b/modules/aaa/mod_authnz_ldap.c @@ -126,9 +126,13 @@ static char* derive_codepage_from_lang (apr_pool_t *p, char *language) charset = (char*) apr_hash_get(charset_conversions, language, APR_HASH_KEY_STRING); - if (!charset) { - language[2] = '\0'; - charset = (char*) apr_hash_get(charset_conversions, language, APR_HASH_KEY_STRING); + /* + * Test if language values like 'en-US' return a match from the charset + * conversion map when shortened to 'en'. + */ + if (!charset && strlen(language) > 3 && language[2] == '-') { + char *language_short = apr_pstrndup(p, language, 2); + charset = (char*) apr_hash_get(charset_conversions, language_short, APR_HASH_KEY_STRING); } if (charset) { diff --git a/modules/cache/mod_cache_socache.c b/modules/cache/mod_cache_socache.c index 11e950285d..0d76760c5b 100644 --- a/modules/cache/mod_cache_socache.c +++ b/modules/cache/mod_cache_socache.c @@ -213,7 +213,8 @@ static apr_status_t read_table(cache_handle_t *handle, request_rec *r, "Premature end of cache headers."); return APR_EGENERAL; } - while (apr_isspace(buffer[colon])) { + /* Do not go past the \r from above as apr_isspace('\r') is true */ + while (apr_isspace(buffer[colon]) && (colon < *slider)) { colon++; } apr_table_addn(table, apr_pstrndup(r->pool, (const char *) buffer diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 7b4cb09e08..11cbe9187a 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -1691,10 +1691,12 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p, "Alert! worker name (%s) too long; truncated to: %s", ptr, wshared->name); } if (PROXY_STRNCPY(wshared->scheme, uri.scheme) != APR_SUCCESS) { - return apr_psprintf(p, "worker scheme (%s) too long", uri.scheme); + ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(010117) + "Alert! worker scheme (%s) too long; truncated to: %s", uri.scheme, wshared->scheme); } if (PROXY_STRNCPY(wshared->hostname, uri.hostname) != APR_SUCCESS) { - return apr_psprintf(p, "worker hostname (%s) too long", uri.hostname); + ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(010118) + "Alert! worker hostname (%s) too long; truncated to: %s", uri.hostname, wshared->hostname); } wshared->flush_packets = flush_off; wshared->flush_wait = PROXY_FLUSH_WAIT; diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c index ff4c9a6f2d..d517020d99 100644 --- a/modules/session/mod_session.c +++ b/modules/session/mod_session.c @@ -510,12 +510,15 @@ static int session_fixups(request_rec * r) */ ap_session_load(r, &z); - if (z && conf->env) { - session_identity_encode(r, z); - if (z->encoded) { - apr_table_set(r->subprocess_env, HTTP_SESSION, z->encoded); - z->encoded = NULL; + if (conf->env) { + if (z) { + session_identity_encode(r, z); + if (z->encoded) { + apr_table_set(r->subprocess_env, HTTP_SESSION, z->encoded); + z->encoded = NULL; + } } + apr_table_unset(r->headers_in, "Session"); } return OK; diff --git a/server/core.c b/server/core.c index b52e9b258a..4af08166f6 100644 --- a/server/core.c +++ b/server/core.c @@ -48,6 +48,7 @@ #include "mod_core.h" #include "mod_proxy.h" #include "ap_listen.h" +#include "ap_regex.h" #include "mod_so.h" /* for ap_find_loaded_module_symbol */ @@ -2847,6 +2848,58 @@ static const char *virtualhost_section(cmd_parms *cmd, void *dummy, return errmsg; } +static const char *set_regex_default_options(cmd_parms *cmd, + void *dummy, + const char *arg) +{ + const command_rec *thiscmd = cmd->cmd; + int cflags, cflag; + + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + if (err != NULL) { + return err; + } + + cflags = ap_regcomp_get_default_cflags(); + while (*arg) { + const char *name = ap_getword_conf(cmd->pool, &arg); + int how = 0; + + if (strcasecmp(name, "none") == 0) { + cflags = 0; + continue; + } + + if (*name == '+') { + name++; + how = +1; + } + else if (*name == '-') { + name++; + how = -1; + } + + cflag = ap_regcomp_default_cflag_by_name(name); + if (!cflag) { + return apr_psprintf(cmd->pool, "%s: option '%s' unknown", + thiscmd->name, name); + } + + if (how > 0) { + cflags |= cflag; + } + else if (how < 0) { + cflags &= ~cflag; + } + else { + cflags = cflag; + } + } + ap_regcomp_set_default_cflags(cflags); + + return NULL; +} + static const char *set_server_alias(cmd_parms *cmd, void *dummy, const char *arg) { @@ -4421,6 +4474,9 @@ AP_INIT_TAKE12("RLimitNPROC", no_set_limit, NULL, OR_ALL, "soft/hard limits for max number of processes per uid"), #endif +AP_INIT_RAW_ARGS("RegexDefaultOptions", set_regex_default_options, NULL, RSRC_CONF, + "default options for regexes (prefixed by '+' to add, '-' to del)"), + /* internal recursion stopper */ AP_INIT_TAKE12("LimitInternalRecursion", set_recursion_limit, NULL, RSRC_CONF, "maximum recursion depth of internal redirects and subrequests"), @@ -4856,6 +4912,8 @@ static int core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptem apr_pool_cleanup_register(pconf, NULL, reset_config_defines, apr_pool_cleanup_null); + ap_regcomp_set_default_cflags(AP_REG_DOLLAR_ENDONLY); + mpm_common_pre_config(pconf); return OK; diff --git a/server/protocol.c b/server/protocol.c index a89e2feb24..6994633297 100644 --- a/server/protocol.c +++ b/server/protocol.c @@ -225,6 +225,11 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, int fold = flags & AP_GETLINE_FOLD; int crlf = flags & AP_GETLINE_CRLF; + if (!n) { + /* Needs room for NUL byte at least */ + return APR_BADARG; + } + /* * Initialize last_char as otherwise a random value will be compared * against APR_ASCII_LF at the end of the loop if bb only contains @@ -238,14 +243,15 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, rv = ap_get_brigade(r->proto_input_filters, bb, AP_MODE_GETLINE, APR_BLOCK_READ, 0); if (rv != APR_SUCCESS) { - return rv; + goto cleanup; } /* Something horribly wrong happened. Someone didn't block! * (this also happens at the end of each keepalive connection) */ if (APR_BRIGADE_EMPTY(bb)) { - return APR_EGENERAL; + rv = APR_EGENERAL; + goto cleanup; } for (e = APR_BRIGADE_FIRST(bb); @@ -263,7 +269,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, rv = apr_bucket_read(e, &str, &len, APR_BLOCK_READ); if (rv != APR_SUCCESS) { - return rv; + goto cleanup; } if (len == 0) { @@ -276,17 +282,8 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, /* Would this overrun our buffer? If so, we'll die. */ if (n < bytes_handled + len) { - *read = bytes_handled; - if (*s) { - /* ensure this string is NUL terminated */ - if (bytes_handled > 0) { - (*s)[bytes_handled-1] = '\0'; - } - else { - (*s)[0] = '\0'; - } - } - return APR_ENOSPC; + rv = APR_ENOSPC; + goto cleanup; } /* Do we have to handle the allocation ourselves? */ @@ -294,7 +291,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, /* We'll assume the common case where one bucket is enough. */ if (!*s) { current_alloc = len; - *s = apr_palloc(r->pool, current_alloc); + *s = apr_palloc(r->pool, current_alloc + 1); } else if (bytes_handled + len > current_alloc) { /* Increase the buffer size */ @@ -305,7 +302,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, new_size = (bytes_handled + len) * 2; } - new_buffer = apr_palloc(r->pool, new_size); + new_buffer = apr_palloc(r->pool, new_size + 1); /* Copy what we already had. */ memcpy(new_buffer, *s, bytes_handled); @@ -329,19 +326,15 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, } } - if (crlf && (last_char <= *s || last_char[-1] != APR_ASCII_CR)) { - *last_char = '\0'; - bytes_handled = last_char - *s; - *read = bytes_handled; - return APR_EINVAL; - } - - /* Now NUL-terminate the string at the end of the line; + /* Now terminate the string at the end of the line; * if the last-but-one character is a CR, terminate there */ if (last_char > *s && last_char[-1] == APR_ASCII_CR) { last_char--; } - *last_char = '\0'; + else if (crlf) { + rv = APR_EINVAL; + goto cleanup; + } bytes_handled = last_char - *s; /* If we're folding, we have more work to do. @@ -361,7 +354,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, rv = ap_get_brigade(r->proto_input_filters, bb, AP_MODE_SPECULATIVE, APR_BLOCK_READ, 1); if (rv != APR_SUCCESS) { - return rv; + goto cleanup; } if (APR_BRIGADE_EMPTY(bb)) { @@ -378,7 +371,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, rv = apr_bucket_read(e, &str, &len, APR_BLOCK_READ); if (rv != APR_SUCCESS) { apr_brigade_cleanup(bb); - return rv; + goto cleanup; } /* Found one, so call ourselves again to get the next line. @@ -395,10 +388,8 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, if (c == APR_ASCII_BLANK || c == APR_ASCII_TAB) { /* Do we have enough space? We may be full now. */ if (bytes_handled >= n) { - *read = n; - /* ensure this string is terminated */ - (*s)[n-1] = '\0'; - return APR_ENOSPC; + rv = APR_ENOSPC; + goto cleanup; } else { apr_size_t next_size, next_len; @@ -411,7 +402,6 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, tmp = NULL; } else { - /* We're null terminated. */ tmp = last_char; } @@ -420,7 +410,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, rv = ap_rgetline_core(&tmp, next_size, &next_len, r, 0, bb); if (rv != APR_SUCCESS) { - return rv; + goto cleanup; } if (do_alloc && next_len > 0) { @@ -434,7 +424,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, memcpy(new_buffer, *s, bytes_handled); /* copy the new line, including the trailing null */ - memcpy(new_buffer + bytes_handled, tmp, next_len + 1); + memcpy(new_buffer + bytes_handled, tmp, next_len); *s = new_buffer; } @@ -447,8 +437,21 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, } } } + +cleanup: + if (bytes_handled >= n) { + bytes_handled = n - 1; + } + if (*s) { + /* ensure the string is NUL terminated */ + (*s)[bytes_handled] = '\0'; + } *read = bytes_handled; + if (rv != APR_SUCCESS) { + return rv; + } + /* PR#43039: We shouldn't accept NULL bytes within the line */ if (strlen(*s) < bytes_handled) { return APR_EINVAL; @@ -487,6 +490,11 @@ AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int flags) apr_size_t len; apr_bucket_brigade *tmp_bb; + if (n < 1) { + /* Can't work since we always NUL terminate */ + return -1; + } + tmp_bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); rv = ap_rgetline(&tmp_s, n, &len, r, flags, tmp_bb); apr_brigade_destroy(tmp_bb); diff --git a/server/util_pcre.c b/server/util_pcre.c index 4d2adef25b..4e707a8b28 100644 --- a/server/util_pcre.c +++ b/server/util_pcre.c @@ -111,6 +111,38 @@ AP_DECLARE(void) ap_regfree(ap_regex_t *preg) * Compile a regular expression * *************************************************/ +static int default_cflags = AP_REG_DOLLAR_ENDONLY; + +AP_DECLARE(int) ap_regcomp_get_default_cflags(void) +{ + return default_cflags; +} + +AP_DECLARE(void) ap_regcomp_set_default_cflags(int cflags) +{ + default_cflags = cflags; +} + +AP_DECLARE(int) ap_regcomp_default_cflag_by_name(const char *name) +{ + int cflag = 0; + + if (ap_cstr_casecmp(name, "ICASE") == 0) { + cflag = AP_REG_ICASE; + } + else if (ap_cstr_casecmp(name, "DOTALL") == 0) { + cflag = AP_REG_DOTALL; + } + else if (ap_cstr_casecmp(name, "DOLLAR_ENDONLY") == 0) { + cflag = AP_REG_DOLLAR_ENDONLY; + } + else if (ap_cstr_casecmp(name, "EXTENDED") == 0) { + cflag = AP_REG_EXTENDED; + } + + return cflag; +} + /* * Arguments: * preg points to a structure for recording the compiled expression @@ -127,12 +159,15 @@ AP_DECLARE(int) ap_regcomp(ap_regex_t * preg, const char *pattern, int cflags) int errcode = 0; int options = PCRE_DUPNAMES; + cflags |= default_cflags; if ((cflags & AP_REG_ICASE) != 0) options |= PCRE_CASELESS; if ((cflags & AP_REG_NEWLINE) != 0) options |= PCRE_MULTILINE; if ((cflags & AP_REG_DOTALL) != 0) options |= PCRE_DOTALL; + if ((cflags & AP_REG_DOLLAR_ENDONLY) != 0) + options |= PCRE_DOLLAR_ENDONLY; preg->re_pcre = pcre_compile2(pattern, options, &errcode, &errorptr, &erroffset, NULL); |